You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步调用场景下如何按顺序加载动态JavaScript文件?

保证动态脚本按顺序加载的解决方案(无需数组缓存)

异步加载动态脚本时,浏览器可能因并行加载特性打乱脚本的加载与执行顺序(例如a2.js和a3.js的加载顺序颠倒),进而引发运行异常。以下针对无法使用数组缓存的场景,提供三种可行的解决方案:

方案1:基于Promise链式调用实现串行加载

利用SYS.SCRIPT.LOAD方法返回Promise的特性,维护一个串行加载的Promise链,确保每个脚本只有在前一个完全加载执行完成后才开始加载。

修改前端监听逻辑:

// 初始化一个已完成的Promise作为链的起点
let loadSequence = Promise.resolve();

LOCAL_COMMUNICATOR.on("RETURN", function(action, data) {
  if (action == "LOAD_SCRIPT") {
    console.log("LOAD_SCRIPT: " + data);
    // 将新的加载任务追加到Promise链,严格保证顺序
    loadSequence = loadSequence.then(() => SYS.SCRIPT.LOAD(data));
  } 
})

原理:每次加载任务都依赖前一个任务的完成状态,从逻辑上强制脚本按接收顺序串行加载执行,无需额外缓存数组。

方案2:通过Node.js与前端的交互确认控制顺序

从通信源头控制脚本发送时机:Node.js仅在收到前一个脚本加载完成的确认后,才发送下一个脚本的加载指令。

Node.js端修改:

function GET_FILES_NAME(path, name_of_go, main_length) {
  fs.readdir(path, function(err, items) {
    let currentScriptIndex = 0;

    // 发送下一个脚本的函数
    function sendNextScript() {
      if (currentScriptIndex >= items.length) return;
      const targetScript = items[currentScriptIndex];
      console.log("VISUAL SCRIPT FOR POST LOAD ::::::::::", targetScript);
      io.sockets.emit(
        "RETURN",
        "LOAD_SCRIPT",
        "cache/" + name_of_go + "/" + targetScript
      );
      currentScriptIndex++;
    }

    // 监听前端加载完成的确认信号,触发下一个脚本发送
    io.sockets.on("SCRIPT_LOADED", sendNextScript);

    // 启动第一个脚本的发送
    sendNextScript();
  });
}

前端LOAD方法修改:

export var SCRIPT = {
  SCRIPT_ID: 0,
  LOAD: async function addScript(src, isAsync) {
    return new Promise((resolve, reject) => {
      var s = document.createElement("script");
      if (typeof isAsync !== 'undefined') s.type = "module";
      s.onload = function () {
        SCRIPT.SCRIPT_ID++;
        console.log('\x1b[36m%s\x1b[0m',
          "Script id loaded [" +
            SCRIPT.SCRIPT_ID +
            "] : " +
            this.src
        );
        var filename = this.src.substring(
          this.src.lastIndexOf("/") + 1,
          this.src.lastIndexOf(".")
        );
        filename = filename.replace(".", "_");
        // 向Node.js发送加载完成的确认信号
        LOCAL_COMMUNICATOR.emit("SCRIPT_LOADED");
        resolve('Async js code block loaded and executed.');
        console.log('LOaded -> ' + filename)
      };
      s.setAttribute("src", src);
      document.body.appendChild(s);
    })
  }
};

原理:通过双向通信的确认机制,从发送端保证脚本的顺序,前端只需按接收顺序处理即可,无需缓存。

方案3:关闭脚本异步加载特性(非模块脚本适用)

对于非模块类型的脚本,设置async=false,强制浏览器按照脚本插入DOM的顺序加载执行。

修改前端LOAD方法:

export var SCRIPT = {
  SCRIPT_ID: 0,
  LOAD: async function addScript(src, isAsync) {
    return new Promise((resolve, reject) => {
      var s = document.createElement("script");
      if (typeof isAsync !== 'undefined') {
        s.type = "module";
      } else {
        // 关闭异步加载,强制按插入顺序执行
        s.async = false;
      }
      s.onload = function () {
        SCRIPT.SCRIPT_ID++;
        console.log('\x1b[36m%s\x1b[0m',
          "Script id loaded [" +
            SCRIPT.SCRIPT_ID +
            "] : " +
            this.src
        );
        var filename = this.src.substring(
          this.src.lastIndexOf("/") + 1,
          this.src.lastIndexOf(".")
        );
        filename = filename.replace(".", "_");
        resolve('Async js code block loaded and executed.');
        console.log('LOaded -> ' + filename)
      };
      s.setAttribute("src", src);
      document.body.appendChild(s);
    })
  }
};

注意:模块脚本(type="module")默认异步加载,此方案对模块脚本不生效,需使用方案1或2。

内容的提问来源于stack exchange,提问作者Nikola Lukic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:45:50