首页 > 解决方案 > 延迟脚本的加载直到承诺完成

问题描述

有没有办法延迟脚本标签的 onload 事件,直到脚本中的一些 Promise 完成?

一点背景:我加载了一个具有以下功能的脚本。在脚本内部调用了一些异步函数,该函数返回一个值。

const loadScript = (src, resolveWithGlobal) =>
  new Promise((resolve) => {
    const script = window.document.createElement("script");
    script.src = src;
    script.async = true;
    script.onload = () => {
      resolve(window[resolveWithGlobal]);
    };

    window.document.body.appendChild(script);
});

const lib = await loadScript("path/to/library1.js", "library2");

加载的脚本看起来类似于这个(它的行为就像加载其他脚本/库的代理)

// library1.js
(async () => {
   await loadScript("path/to/library2.js", "library2");
})();

目前我只是返回要查找并loadScript在同一个文件中进行两次调用,如果我以后想删除间接,这有点难看

const lib1 = loadScript("lib1.js", "lib1");
const lib = loadScript(lib.path, "lib2");

标签: javascriptasynchronous

解决方案


对于一般情况,您可以将解析器函数放在窗口上,其名称不会与任何其他名称发生冲突——也许将随机字符串放入脚本标签的数据集中。然后让脚本在运行时检查其脚本标签中的唯一名称,并在其异步操作完成时调用解析器。

const loadScript = (src, resolveWithGlobal) =>
    new Promise((resolve) => {
        const script = window.document.createElement("script");
        script.src = src;
        script.async = true;
        const uniqueId = Math.random().toString(36).substring(7);
        script.dataset.uniqueId = uniqueId;
        window[uniqueId] = () => {
            delete window[uniqueId]
            return () => {
                resolve(window[resolveWithGlobal]);
            };
        };
        script.onload = () => {
            // If resolver hasn't been retrieved by the library, do it now:
            window[uniqueId]?.()();
        };

        window.document.body.appendChild(script);
    });
const lib1 = loadScript("lib1.js", "lib1");
// lib1.js
const resolve = window[document.currentScript.uniqueid]();
loadScript("path/to/library2.js", "library2")
  .then(resolve);

如果脚本不执行任何异步操作,则它不需要对窗口上的解析器执行任何特殊操作 -loadScript在这种情况下,当脚本加载时会调用它。


推荐阅读