如何判断一个脚本是否完成加载?



我有一个函数,在某些时候做document.getElementsByTagName("script"),它想知道每个脚本是否已经加载。

我想得到一个承诺,如果它被加载和挂起,如果它仍然在进行,那么我可以用.then(...)附加下一步,并确保它们被执行。

我想我可以附加一个加载事件,但是如果脚本已经加载了,我就永远不会得到这个事件。

我可以通过做一些假设来解决这个问题,即我控制所有动态脚本标签,对于静态脚本标签,文档。currentScript总是到目前为止加载的最后一个脚本,所有前面的脚本都已经加载完成,假设它们都是静态的。但这些假设可能并不总是正确的。

那么,是否有一种方法来检查状态并生成承诺,根据状态将开始作为完成(解决)或由加载事件触发完成?

添加脚本元素的DOM将导致异步加载,没有立即在代码之前使用它们。您需要为脚本的onload事件使用回调函数。下面是这样做的一个示例帮助函数。

function loadAsync(url, callback) {
var s = document.createElement('script');
s.setAttribute('src', url);
s.onload = callback;
document.head.insertBefore(s, document.head.firstElementChild);
}

MutationObserver可用于为动态创建的脚本元素添加加载事件侦听器。

Map用于存储加载事件时承诺,将解决火灾。

const scriptMap = new Map();
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeName === 'SCRIPT' && node.getAttribute('src') != null) {
scriptMap.set(node, new Promise(resolve => {
node.addEventListener('load', () => resolve());  
}));
}
}    
}  
});

开始观察:

observer.observe(document, {
childList: true,
subtree: true
});

定义一个函数,如果脚本还没有加载或解析,返回一个承诺,该承诺将挂起:

const load = script => scriptMap.get(script) ?? Promise.resolve();

使用例子:

const scriptElements = document.getElementsByTagName('script');
for (let script of scriptElements) {
await load(script);
}

使用scriptMap.values()获取动态创建脚本的承诺:

await Promise.all(scriptMap.values());

为了效率起见,当不再需要时停止观察:

observer.disconnect();

相关内容

  • 没有找到相关文章

最新更新