今天,我对 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.json
和 app.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')
。
理解为什么一定是这种情况的一个简单方法是考虑如果我们在
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/?
我们可能希望这两个调用返回相同的内容 - 但如果 fetch 相对于所包含的文件,那么 logFetch 将请求
js/helper/data.json
而不是与 fetch 一致的内容。
如果 fetch 可以感知从哪里调用它,那么要实现 logFetch 等帮助程序库,JavaScript 需要一系列新的调用者位置感知功能。
相比之下,执行相对于 HTML 文件的获取可提供更高的一致性。
CSS 的工作方式有所不同,因为它没有方法调用的复杂性:您无法创建转换其他 CSS 模块的“辅助 CSS 模块”,因此相对路径的想法在概念上更加清晰。
这不完全是一个建议,因为它依赖于一些不能保证在任何地方都有效或在未来继续有效的东西,但是它在我需要它的地方对我有用,并且可能对你有帮助。
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
})
import.meta.resolve()
获取与 JavaScript 模块相关的资源。