
本文介绍一种基于 async/await 的现代、简洁且可靠的方案,用于确保多个外部 javascript 文件严格按序加载与执行,每个脚本必须完全完成(包括其内部异步逻辑)后,下一个才开始加载。
本文介绍一种基于 async/await 的现代、简洁且可靠的方案,用于确保多个外部 javascript 文件严格按序加载与执行,每个脚本必须完全完成(包括其内部异步逻辑)后,下一个才开始加载。
在 Web 开发中,当需要按特定顺序执行多个外部脚本(例如依赖链明显的初始化模块、分阶段配置或逐步增强的业务逻辑),仅靠 <script defer> 或简单动态插入无法保证<strong>执行完成(而非仅加载完成)。defer 仅保证解析顺序,不等待脚本内异步操作(如 setTimeout、fetch、Promise)结束;而传统事件监听方式(如 dispatchEvent + addEventListener)则代码冗余、可维护性差,且难以扩展至 20+ 脚本。</script>
推荐使用 async/await 驱动的串行加载方案,核心优势在于:
✅ 真正等待脚本执行完毕(onload 触发即表示脚本已解析并同步执行完顶层代码;若脚本内含异步逻辑,需开发者自行确保其完成后再 resolve)
✅ 语法简洁、逻辑清晰、易于调试和扩展
✅ 天然支持错误处理(try/catch)与超时控制
✅ 推荐实现(完整可运行示例)
<title>Sequential Script Loading</title><script>
async function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.type = 'module'; // 可选:启用 ES 模块支持(如需 import/export)
script.onload = () => resolve();
script.onerror = (e) => reject(new Error(`Failed to load ${src}: ${e.message}`));
document.head.appendChild(script);
});
}
async function loadScriptsSequentially(scripts) {
for (const src of scripts) {
console.log(`⏳ Starting load: ${src}`);
try {
await loadScript(src);
console.log(`✅ Completed: ${src}`);
} catch (error) {
console.error(`❌ Failed at ${src}:`, error);
throw error; // 中断后续加载(如需容错可改为 continue)
}
}
console.log('? All scripts loaded and executed sequentially.');
}
// 示例:20 个脚本?只需扩展数组即可
const scriptUrls = [
'script1.js',
'script2.js',
'script3.js'
// ... 更多脚本路径
];
loadScriptsSequentially(scriptUrls);
</script><h1>Hello world</h1>
⚠️ 关键注意事项
-
onload ≠ 脚本内所有异步操作完成:<script> 的 onload 事件仅表示该文件已下载、解析并执行完<strong>同步代码。若 script1.js 内部启动了 setTimeout 或 fetch,onload 不会等待它们。因此,<strong>需确保每个脚本自身负责“就绪通知”——常见做法是导出一个 init() 函数,并在 onload 后显式调用它并 await 其返回的 Promise:</script>
// script1.js export async function init() { await new Promise(resolve => setTimeout(resolve, 3000)); console.log('script1 fully ready'); }对应主逻辑需调整为:
await loadScript(src); if (typeof window.init === 'function') await window.init(); // 假设全局暴露 // 或更健壮的方式:通过动态 import(需 type="module")
错误中断策略:示例中使用 throw 中断整个流程。若允许部分失败,可将 try/catch 移至循环内并 continue。
性能权衡:串行加载牺牲并行下载优势。如脚本间无强依赖,优先考虑 Promise.all() 并行加载 + 依赖排序执行。
现代替代方案:对新项目,强烈建议采用 ES Modules + 构建工具(如 Vite/Webpack),通过静态 import 实现天然顺序与依赖管理,避免手动脚本编排。
综上,async/await + Promise 封装是目前最简洁、可读性强、符合现代 JavaScript 实践的顺序加载方案,兼顾可靠性与可维护性,适用于从 3 个到数十个脚本的生产级场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











