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

如何强制Chrome/Firefox的JS引擎等待动态脚本加载执行完成?

问题:脚本加载顺序失控,make_components()提前执行

背景与目标

我写了一个loader.js脚本,想要按「变量定义→组件定义→组件渲染」的顺序加载管理组件的JS文件,代码如下:

const loadScript = (FILE_URL, async = true, type = "text/javascript") => {
    return new Promise((resolve, reject) => {
        try {
            const scriptEle = document.createElement("script");
            scriptEle.type = type;
            scriptEle.async = async;

            //scriptEle.async = false; // 我也试过这行
            scriptEle.defer = true;

            scriptEle.src = FILE_URL;

            scriptEle.addEventListener("load", (ev) => {
                resolve({ status: true });
            });

            scriptEle.addEventListener("error", (ev) => {
                reject({
                    status: false,
                    message: `Failed to load the script ${FILE_URL}`
                });
            });

            document.body.appendChild(scriptEle);
        } catch (error) {
            reject(error);
        }
    });
};

$(document).ready(function () {
    setTimeout(proceed, 1); // 等文档完全就绪
});

async function proceed() {
    await loadVars();              // 加载变量定义
    await loadComponents();        // 加载组件定义 
    await make_components();       // 渲染组件
}

function make_components() {
    switch (monitorType) {         // monitorType应该在loadVars执行后定义(控制台日志也确认了这一点)
        case 1 :
            addMobileHeader(wfull, hfull * 0.1);
            addMobileHeroBlock(wfull, hfull* 0.7);
            break;
    }
}

function loadVars() {
    loadScript("variables.js").then( data  => {
        console.log("Variables: Script loaded successfully", data);
    })
    .catch( err => {
        console.error(err);
    });
}

function loadComponents() {
    loadScript("components_mobile.js").then( data  => {
        console.log("Components (mobilephone): Script loaded successfully _ mobile", data);
    })
    .catch( err => {
        console.error(err);
    });

    loadScript("components_wide.js").then( data  => {
        console.log("Components (widescreen):Script loaded successfully _ wide", data);
    })
    .catch( err => {
        console.error(err);
    });
}

核心问题

make_components()总是在loadVars执行完成前就被触发,导致找不到monitorType等变量。

尝试过的方法

我本来以为先添加的variables.js会先执行,后续延迟加载的文件会按顺序执行,然后make_components再启动。我知道可以用.then链式调用,但那样代码会变得难以调试。

需求

有没有办法让Chrome/Firefox的JS引擎强制等待脚本完全加载并执行?最好不用第三方库。


解决方法

问题根源

你的loadVars和loadComponents函数没有返回Promise,导致await根本起不到等待作用——await后面必须跟Promise对象,否则会直接当成已完成的Promise处理,所以proceed会直接跳到下一步,完全不等脚本加载完成。

修复步骤

  1. 让loadVars返回Promise
    修改loadVars,直接返回loadScript的Promise,确保await能捕获到加载状态:
function loadVars() {
    return loadScript("variables.js")
        .then(data => {
            console.log("Variables: Script loaded successfully", data);
        })
        .catch(err => {
            console.error(err);
            throw err; // 抛出错误让上层await捕获,避免后续流程继续执行
        });
}
  1. 让loadComponents等待所有脚本加载完成
    loadComponents里加载了两个脚本,需要用Promise.all确保两个脚本都加载完成后再继续:
function loadComponents() {
    const mobilePromise = loadScript("components_mobile.js")
        .then(data => {
            console.log("Components (mobilephone): Script loaded successfully _ mobile", data);
        })
        .catch(err => {
            console.error(err);
            throw err;
        });

    const widePromise = loadScript("components_wide.js")
        .then(data => {
            console.log("Components (widescreen):Script loaded successfully _ wide", data);
        })
        .catch(err => {
            console.error(err);
            throw err;
        });

    return Promise.all([mobilePromise, widePromise]);
}
  1. 清理脚本加载的async/defer设置
    你同时设置了async和defer,会导致行为混乱:
  • 如果async=true,浏览器会异步加载脚本,加载完成后立即执行,顺序无法保证
  • 要按顺序加载,应该把async设为false,并且去掉defer(同步加载的脚本不需要defer)

修改loadScript的默认参数或调用时传参:

// 方案1:修改函数默认值
const loadScript = (FILE_URL, async = false, type = "text/javascript") => {
    // ... 原代码
    // 移除 scriptEle.defer = true;
}

// 方案2:调用时指定async=false
return loadScript("variables.js", false)

最终效果

修改后,proceed函数里的await会真正等待loadVars完成(变量脚本加载并执行),再等待loadComponents的两个脚本都加载完成,最后才执行make_components,此时monitorType等变量已经定义完成。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:20:21