【发布时间】:2020-05-05 11:38:02
【问题描述】:
我对在特定 ES6 模块加载场景中未触发的事件感到困惑。这是一个支持我的示例的 Codepen 项目: https://codepen.io/fchristant/project/editor/AYQkGJ
考虑这个非常简单的模块app.js:
console.log('in module');
document.addEventListener('DOMContentLoaded', (event) => {
console.log('DCL:2');
});
我正在使用来自文档头部脚本标签的动态 ES6 导入:
<script>
(async () => {
const module = await import("./js/app.js");
console.log('async done');
})();
</script>
所以,这个调用代码是一个非模块(同步脚本)动态加载一个模块。因为它在文档的头部而不是异步或延迟,所以我希望它立即运行,并以阻塞的方式运行。
这是我的期望,但不是正在发生的事情。特别是,问题是模块中的事件永远不会被触发。看起来是因为来不及听了,事件已经发生了。鉴于文档头部的阻止脚本,这怎么可能?它看起来是非阻塞的,但我不明白为什么。
要清楚,讨论不是这是否是一个好主意,我最感兴趣的是为什么这不起作用的概念性答案。或者换个说法:非模块脚本如何以同步方式动态加载模块?
【问题讨论】:
-
如果您想以 同步 方式加载脚本,那么您只需将其添加到文档中的
<script>标记中即可。模块的优点是您可以在单个脚本中使用与其他脚本不同的功能,方法是导入它们并在那里调用它们。在您的情况下,您的文件已下载,但您的app.js脚本中没有导出函数,因此没有什么可调用或使用的。 -
那我应该导出什么?模块内的代码显然正在运行,因为打印了“模块内”。然而,当它运行时,domcontentloaded 已经发生了。我仍然不知道为什么会这样。
-
异步导入你的模块会告诉浏览器它不应该在发出
DOMContentLoaded事件之前等待模块。这与将async属性添加到SCRIPT标记几乎相同。如果您希望您的模块处理DOMContentLoaded事件 - 您不应该使用异步导入。 -
async函数是非阻塞的 - 所以没有“头部阻塞脚本” -
您可以将
domcontentloaded事件监听器放在您的主脚本中,并在事件发生时导入您的模块。
标签: javascript ecmascript-6 es6-modules