javascript - 如何按特定顺序动态加载多个脚本?

标签 javascript typescript

我需要动态地(在 TypeScript 和 JavaScript 中)加载 x 个脚本(假设本例中有 6 个)。

前 2 个脚本被后 4 个脚本使用。所以我必须确保在加载最后 4 个脚本之前加载脚本 1 和 2。

var scripts = [
  { "path": "f1.js", "isDependency": true },
  { "path": "f2.js", "isDependency": true },
  { "path": "f3.js", "isDependency": false },
  { "path": "f4.js", "isDependency": false },
  { "path": "f5.js", "isDependency": false },
  { "path": "f6.js", "isDependency": false }
];

我有一个加载脚本的异步函数,但我在设置异步/等待时遇到问题,或者无法 promise 等待前 2 个脚本加载,然后让其他脚本以任何顺序加载。

private async loadJsFileAsync(filePath: string) {
  return new Promise((resolve, reject) => {
    if (!document.getElementById(filePath)) {
      var script = document.createElement('script');

      script.onload = function () {
        // mark with attribute so we know that it's loaded
        script.attributes["data-loaded"] = "true";
        resolve();
      }
      script.onerror = function (err) {
        reject(err);
      }

      script.type = "text/javascript";
      script.src = filePath
      script.id = filePath;
      document.getElementsByTagName('head')[0].appendChild(script);

    } else {
      // file processed, but check to see it actually loaded
      var s1 = <HTMLScriptElement>document.getElementById(filePath);
      var loadedAttribute = s1.attributes["data-loaded"] === "true";
      if (loadedAttribute) {
        resolve();
      } else {

        // add event listeners (in addition to the existing ones)
        s1.addEventListener("load", function () {
          resolve();
        });
        s1.addEventListener("error", function (err) {
          reject(err);
        });
      }
    }
  });
}

目前我通过以下方式仅将异步函数与一个必需的脚本一起使用:

this.loadJsFileAsync("f1.js").then(value => {

  // load other files
  loadJsFile("f3.js");
  loadJsFile("f4.js");
  loadJsFile("f5.js");
  loadJsFile("f6.js");
});

private loadJsFile(filePath: string) {
  var script = document.createElement('script');
  script.type = "text/javascript";
  script.src = filePath + this.version();
  script.id = filePath;
  document.getElementsByTagName('head')[0].appendChild(script);
}   

最佳答案

首先,为什么不使用 requirejs 或其他模块加载器?它们为您提供链接脚本的能力,以便首先加载依赖项。其次,我认为这就是您想要的:

这里肯定有改进和优化的空间,但它应该会给你想要的结果。

class Script {
    constructor(path, dependencyOrder) {
        this.path = path;
        this.dependencyOrder = dependencyOrder;
    }
}
class ScriptLoader {
    constructor() {
        this.scripts = [];

    }
    addScript(script) {
        const exists = this.scripts.find( s => s.path.toLowerCase() === script.path.toLowerCase());
        if (!exists) {
            this.scripts.push(script);
        }
    }
    async loadScripts() {
        if (Array.isArray(this.scripts)) {
            const orderedScripts = this.orderScriptsByDependency();
            let scriptsLoaded = false;
            let counter = 0;
            while (!scriptsLoaded) {
                const _script = orderedScripts[counter]
                await this.loadScript(_script, _script.dependencyOrder > -1);
                counter += 1;
                scriptsLoaded = counter === orderedScripts.length;
            }
        }
    }
    async loadScript(script, waitToLoad) {
        return new Promise( (resolve, reject) => {
            const scriptTag = document.createElement('script');
            scriptTag.src = script.path;
            if (waitToLoad) {
                scriptTag.async = true;
                document.body.appendChild(scriptTag);
                scriptTag.onload = () => { resolve(); }
            } else {
                document.body.appendChild(scriptTag);
                resolve();
            }
        } );
    }
    orderScriptsByDependency() {
        if (Array.isArray(this.scripts)) {
            return this.scripts.sort( (a, b) => {
                return a.dependencyOrder - b.dependencyOrder;
            });
        }
        return null;
    }
}

用法

class IndexView {
    constructor() {
        this.loader = new ScriptLoader();
        this.init();
    }
    async init() {
        this.loader.addScript(new Script('scripts/script0.js', 0));
        this.loader.addScript(new Script('scripts/script1.js', 1));
        this.loader.addScript(new Script('scripts/script2.js', 2));
        await this.loader.loadScripts();
    }
}

Requirejs

关于javascript - 如何按特定顺序动态加载多个脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55602445/

相关文章:

typescript - VSCODE 将警告显示为错误

html - Angular4+ 在 HTML 模板中显示/隐藏子元素

javascript - html5不兼容浏览器测试

javascript - NodeJS : Input values not reset to their given values

javascript - 如何在 Intl.NumberFormat 中获取正数的前导 '+'?

javascript - 在 TypeScript 中编写 npm 模块

javascript - TypeScript 扩展类,行为不符合逻辑

javascript - 如何进行多个正则表达式替换

javascript - React - 在 map 函数中表达预期

javascript - 使用 jQuery 选择具有特定类的第一个和最后一个元素