0

在我的网站上,我使用 javascript 模块,根据 MDN ,默认情况下这些模块是延迟的。我有一些额外的 javascript,只有在这些模块加载并执行后才能安全执行。MDN在这里指出延迟的脚本执行保证在DOMContentLoaded事件触发时已经发生。此外,这里建议您还可以考虑此事件已经触发的情况,如下所示:

function doSomething() {
  console.info('DOM loaded');
}

if (document.readyState === 'loading') {  // Loading hasn't finished yet
  document.addEventListener('DOMContentLoaded', doSomething);
} else {  // `DOMContentLoaded` has already fired
  doSomething();
}

上面的块似乎是我正在寻找的。但是 MDN 上其他地方的文档让我不确定这是否真的正确。例如,为什么readystate上面的检查寻找loading而不是loadingOR interactive?上的文档readystateloading紧随其后interactive,并且处于“脚本、图像、样式表和框架interactive等子资源仍在加载”状态。

因此,在我看来,这里存在不一致之处。建议的readystate检查不足以保证DOMContentLoaded已触发,或者DOMContentLoaded不足以保证延迟脚本已完成。

4

2 回答 2

1

When readyStateis at least interactive,这意味着文档已被完全解析,并且源 HTML 中的所有元素现在都存在于 DOM 中。

通常,实现此解决方案的人这样做是因为他们试图将侦听器附加到元素,并且需要等待所有元素都存在于 DOM 中 - 所以他们需要做的就是检查document.readyState === 'loading'.

如果您还想等待<script type="module">脚本运行,这是一个不同的问题,有不同的解决方案。

到目前为止,最好的方法是在模块中为您的应用程序设置一个入口点,这样您就不必担心加载顺序 - 它会正常工作。

如果您真的必须确定所有模块脚本何时从非模块脚本运行(我不推荐),您必须遍历它们并监听它们的load事件。

// run this at the end of the body -
// once all script tags exist, but before they've run
Promise.all(
  [...document.querySelectorAll('script[type="module"]')]
    .map(script => new Promise(
      resolve => script.addEventListener('load', resolve)
    ))
)
  .then(() => {
    // all module scripts are loaded
   })

但这很复杂,可能不是一个好方法。

如果您改为监听load窗口的事件,您还将等待所有其他资源也加载(图像和样式表等),这是不可取的。

于 2022-01-23T01:15:08.183 回答
0
 import "other-module";
 // module is guaranteed to be loaded here

通过导入模块,可以保证在导入运行的模块之前加载它。

于 2022-01-23T01:47:00.800 回答