
本文对比 import() 动态导入与手动创建 标签加载 JS 的核心差异,重点分析代码分割能力、运行时性能、浏览器兼容性及构建工具协同效应,帮助开发者在实际项目中做出技术选型决策。
本文对比 import() 动态导入与手动创建 <script> 标签加载 js 的核心差异,重点分析代码分割能力、运行时性能、浏览器兼容性及构建工具协同效应,帮助开发者在实际项目中做出技术选型决策。</script>
在现代前端工程实践中,按需加载 JavaScript 模块是优化首屏性能与资源利用率的关键手段。import()(动态导入)与手写 loadScript() 函数虽都能触发网络请求并执行脚本,但二者在设计定位、运行机制与工程价值上存在本质区别。
✅ import():标准、声明式、可被构建工具深度优化
import() 是 ECMAScript 标准语法(ES2020+),返回一个 Promise,用于异步加载模块:
// 自动触发 Webpack/Vite/Rollup 的代码分割
const { default: Chart } = await import('chart.js');
const utils = await import('./utils.js');
其核心优势在于静态可分析性:构建工具能识别 import() 调用位置,自动生成独立 chunk 文件(如 chunk-abc123.js),并注入智能加载逻辑(如预加载、缓存控制、错误重试)。更重要的是,它支持完整的模块语义——导出/导入、tree-shaking、类型推导(TypeScript)、热更新(HMR)等,是真正意义上的“模块级”按需加载。
⚠️ 手动 loadScript():灵活但原始,仅加载全局脚本
你提供的示例函数本质上是传统 <script> 注入方式的 Promise 封装:</script>
function loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.src = url;
script.onload = () => resolve();
script.onerror = reject;
document.head.appendChild(script);
});
}
// 使用示例(仅适用于无模块系统的 UMD/IIFE 脚本)
await loadScript('https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js');
// 注意:此时 Chart 不是 ES 模块,需从 window.Chart 访问,无法 tree-shaking
该方式完全绕过模块系统,加载的脚本以全局变量形式运行,无法参与构建时优化(如代码分割、依赖分析、摇树),也无法保证模块作用域隔离或副作用控制。它适合加载 CDN 上的第三方库(尤其无 ESM 版本时),但不适合作为应用内部模块的加载方案。
? 性能对比:不是“谁更快”,而是“谁更智能”
单纯比较网络请求耗时意义有限——两者底层都走 HTTP 请求。真正的性能差异体现在:
- 首屏加载:import() 支持预加载()、优先级调度与懒加载策略;手动脚本无此能力。
- 资源复用:import() 加载的模块可被浏览器缓存并跨页面复用;手动脚本若未设置正确 Cache-Control 头,易重复下载。
- 执行开销:import() 加载后自动解析模块图;手动脚本需开发者自行管理依赖顺序与全局污染。
? 兼容性与工程建议
- 浏览器支持:import() 已被 Chrome 63+、Firefox 67+、Safari 11.1+、Edge 79+ 原生支持(caniuse.com)。若需支持 IE 或旧版 Safari,应配合 @babel/plugin-syntax-dynamic-import + @babel/preset-env 编译,并启用 dynamicImportNode 配置生成兼容代码。
- 构建工具协同:Webpack/Vite 等默认将 import() 视为分割点。无需额外配置即可生成 .js chunk,并支持魔法注释(如 /* webpackChunkName: "charts" */)提升可维护性。
-
何时用 loadScript()?
- 加载不提供 ESM 版本的 CDN 库(如老版本 jQuery);
- 实现微前端子应用加载(需沙箱隔离);
- 构建时无法预知 URL 的动态路径(如用户上传的插件脚本)。
✅ 总结:优先选择 import(),慎用手动加载
- ✅ 对于项目内部模块、支持 ESM 的第三方包 → 坚定使用 import();它带来标准化、可维护性与构建优化红利。
- ⚠️ 对于无 ESM 的外部脚本或特殊场景 → 可用 loadScript(),但需自行处理错误、缓存、全局命名冲突等问题。
- ❌ 不要混用二者管理同一类模块(如既用 import() 加载 Chart.js 又用 loadScript() 加载同版本),避免重复下载与状态不一致。
最终,性能优化的起点不是“选哪个 API”,而是“是否让构建工具和浏览器协同工作”。import() 正是为此而生的标准答案。











