在 Javascript 中提取的相对路径

Relative paths with fetch in Javascript

我今天在 Javascript 中对相对路径的体验感到惊讶。我将情况归结为以下几点:

假设您的目录结构如下:

app/
   | 
   +--app.html
   +--js/
        |
        +--app.js
        +--data.json

我的app.html所做的只是运行js/app.js

<!DOCTYPE html>
<title>app.html</title>
<body>
<script src=js/app.js></script>
</body>

app.js 加载 JSON 文件并将其粘贴在 body:

的开头
// js/app.js
fetch('js/data.json') // <-- this path surprises me
  .then(response => response.json())
  .then(data => app.data = data)

数据有效JSON,只是一个字符串:

"Hello World"

这是 fetch 的一个非常小的用法,但令我惊讶的是我传递给 fetch 的 URL 必须相对于 app.html 而不是相对于 app.js。我希望这条路径有效,因为 data.jsonapp.js 在同一目录中 (js/):

fetch('data.json') // nope

是否有解释为什么会这样?

当您说 fetch('data.json') 时,您实际上是在请求 http://yourdomain.com/data.json,因为它与您发出请求的页面相关。您应该以正斜杠开头,这将指示该路径是相对于域根目录的:fetch('/js/data.json')。或者完全符合您的域 fetch('http://yourdomain.com/js/data.json').

这不完全是一个建议,因为它依赖于一些不能保证在任何地方都有效或在未来继续有效的东西,但是它在我需要它的地方对我有用而且它可能对你有帮助。

const getRunningScript = () => {
    return decodeURI(new Error().stack.match(/([^ \n\(@])*([a-z]*:\/\/\/?)*?[a-z0-9\/\]*\.js/ig)[0])
}

fetch(getRunningScript() + "/../config.json")
  .then(req => req.json())
  .then(config => {
    // code
  })

理解为什么一定是这种情况的一种简单方法是考虑如果我们在 app/js/helper/logfetch.js 中编写辅助函数会发生什么:

// app/js/helper/logfetch.js
function logFetch(resource) {
    console.log('Fetching', resource);
    return fetch(resource);
}

现在,考虑一下如果我们使用来自 app/js/app.js 的 logFetch 会发生什么:

// app/js/app.js
fetch('data.json');    // if this is relative to js/, then ...
logFetch('data.json'); // should this be relative to js/ or js/helper/?

我们可能希望这两个对 return 的调用是同一件事 - 但如果 fetch 是相对于包含的文件,那么 logFetch 将请求 js/helper/data.json 而不是与 fetch 一致的东西。

如果 fetch 可以 感知从哪里调用它,那么要实现 logFetch 等辅助库,JavaScript 需要一系列新的呼叫者位置感知功能。

相比之下,相对于 HTML 文件执行提取可提供更高的一致性。

CSS 的工作方式不同,因为它没有方法调用的复杂性:您无法创建转换其他 CSS 模块的“助手 CSS 模块”,因此相对路径的概念在概念上更清晰。