
本文介绍一种基于 async/await 的现代方案,用于确保多个外部 JavaScript 文件严格按序加载、执行并等待完成后再加载下一个,避免回调嵌套与事件监听的复杂性。
本文介绍一种基于 `async/await` 的现代方案,用于确保多个外部 javascript 文件严格按序加载、执行并等待完成后再加载下一个,避免回调嵌套与事件监听的复杂性。
在前端开发中,有时需要按特定顺序加载并执行多个外部脚本(例如依赖链明确的初始化模块、分阶段的 SDK 加载或需严格时序控制的业务逻辑)。虽然 <script defer> 能保证执行顺序与 DOM 中声明顺序一致,但它<strong>不保证脚本内容执行完毕后才开始下一个脚本的加载或执行——尤其当脚本内含异步操作(如 setTimeout、fetch 或自定义 Promise)时,仅靠 defer 无法满足“前一个彻底完成 → 后一个才启动”的强序要求。</script>
更简洁、健壮且符合现代 JavaScript 实践的解决方案是:使用 async/await 配合动态创建 <script> 元素,并通过 onload 事件 resolve Promise,实现真正的串行控制流</script>。
以下是一个完整、可复用的实现:
<html>
<head>
<title>按序加载脚本</title>
<script>
// 封装单个脚本加载为 Promise
async function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.type = 'module'; // 可选:若脚本使用 ES 模块语法,建议添加
script.onload = () => {
console.log(`✅ 已加载并执行完毕: ${src}`);
resolve();
};
script.onerror = (err) => {
console.error(`❌ 脚本加载失败: ${src}`, err);
reject(new Error(`Failed to load script: ${src}`));
};
document.head.appendChild(script);
});
}
// 串行加载脚本列表
async function loadScriptsSequentially(scripts) {
for (const src of scripts) {
try {
await loadScript(src);
} catch (error) {
console.error(`中断于 ${src}:`, error.message);
throw error; // 可根据需求改为 continue 或降级处理
}
}
console.log('? 所有脚本已按序加载并执行完成');
}
// 使用示例:支持任意长度数组(如 20 个脚本)
const scriptUrls = [
'script1.js',
'script2.js',
'script3.js'
// ... 更多脚本
];
// 启动加载流程
loadScriptsSequentially(scriptUrls);
</script>
</head>
<body>
<h1>Hello world</h1>
</body>
</html>✅ 优势说明:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
立即学习“Java免费学习笔记(深入)”;
- 语义清晰:await loadScript(...) 直观表达“等待此脚本完全就绪”,逻辑线性无嵌套;
- 错误可控:每个 loadScript() 都有独立 catch 分支,便于定位失败节点并做重试或告警;
- 扩展性强:轻松适配 3 个或 20 个脚本,无需修改结构;
- 兼容性好:只要浏览器支持 async/await(Chrome 55+、Firefox 52+、Safari 10.1+),即可运行;
- 不依赖全局事件:避免手动 dispatchEvent 和 addEventListener,减少命名冲突与内存泄漏风险。
⚠️ 注意事项:
- 若脚本本身包含顶级 await(ES 模块顶层 await),需确保 <script type="module">,并在 loadScript 中显式设置 script.type = 'module'; </script>
- 动态插入的脚本默认以 text/javascript 执行,不参与 defer/async 属性解析,因此本方案天然规避了其行为不确定性;
- 生产环境建议增加超时机制(如 AbortController + setTimeout 包裹 Promise),防止某脚本长期挂起阻塞后续流程;
- 对于纯静态资源(如无副作用的工具库),若仅需加载顺序而不要求执行完成,则 defer 仍是最轻量方案;但本文聚焦「执行完成即触发下一环节」这一更强约束场景。
综上,利用 async/await 驱动动态脚本加载,是以最小认知成本达成最高可靠性的标准实践,推荐作为顺序执行脚本的首选模式。

















