动态加载 JS 脚本方法对比
在前端开发中,我们经常需要在一个 JavaScript 文件中动态加载其他外部 JS 文件(而且要等加载成功后执行后续的逻辑)。主要有两种方式可以实现:使用<script>
标签和使用fetch
API。本文将对比这两种方法的异同、适用场景和潜在问题。
1. Script 标签加载方式
基本原理
通过动态创建<script>
标签并设置其src
属性,将标签添加到 DOM 中,浏览器会自动加载并执行该脚本。
代码示例
function loadScriptWithTag(url, callback) {
const script = document.createElement("script");
script.src = url;
// 加载成功回调
script.onload = function () {
console.log(`脚本加载成功: ${url}`);
if (callback) callback(true);
};
// 加载失败回调
script.onerror = function () {
console.error(`脚本加载失败: ${url}`);
if (callback) callback(false);
};
// 添加到文档中开始加载
document.head.appendChild(script);
}
// 自执行
loadScriptWithTag(
"https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js",
function (success) {
console.log("脚本加载成功:", success);
// 确保加载成功,执行后续的逻辑
console.log(_.join(["a", "b", "c"], "~"));
}
);
优点
跨域支持:不受同源策略限制,可以加载任何域的脚本
全局作用域:加载的脚本直接在全局作用域中执行,自动注册全局对象和函数
浏览器缓存:浏览器会自动缓存脚本文件,提高重复访问性能
执行可靠:加载完成后立即执行,执行环境与主页面一致
缺点
无法访问脚本内容:只能执行脚本,无法直接获取或修改脚本内容
无法预处理:无法在执行前对代码进行修改或检查
错误处理有限:出错时只能知道加载失败,无法获得详细错误信息
2. Fetch API 加载方式
基本原理
使用fetch
API 获取脚本文件内容作为文本,然后使用eval
或Function
构造函数将文本作为 JavaScript 执行。
代码示例
function loadScriptWithFetch(url) {
return fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.text();
})
.then((code) => {
// 使用eval执行代码
console.log(`脚本加载成功: ${url}`);
eval(code);
if ("判断一下脚本里面的方法是否存在") {
// 确保加载成功,执行后续的逻辑
}
return true;
})
.catch((error) => {
console.error(`脚本加载失败: ${url}`, error);
return false;
});
}
调用 eval(code) 时,浏览器会立即、同步地解析并执行这段字符串代码,也就是说:
它会阻塞当前线程,直到执行完成。
如果里面有语法错误或运行错误,会立即抛出异常。
如果里面包含函数定义、变量声明等,执行完成后立即生效。
优点
内容可见:可以访问和修改脚本内容后再执行
更好的错误处理:可以捕获 HTTP 错误和响应细节
可以预处理:可以在执行前对代码进行分析、转换或注入依赖
缺点
跨域限制:受同源策略限制,加载跨域脚本需要目标服务器配置 CORS
作用域问题:通过 eval 执行的代码可能在不同的词法环境中,导致全局变量和函数无法正确注册
安全限制:现代浏览器对 eval 有更多限制,某些环境下可能被限制使用
3. 比较和适用场景
特性 | Script 标签 | Fetch API |
---|---|---|
跨域加载 | ✅ 支持 | ❌ 需要 CORS |
执行可靠性 | ✅ 高 | ❌ 可能有作用域问题 |
内容可修改 | ❌ 不可修改 | ✅ 可修改 |
错误处理 | ❌ 简单 | ✅ 详细 |
适用场景推荐
使用 Script 标签加载的场景:
加载第三方库和框架
需要在全局作用域中注册对象或函数
需要跨域加载脚本
加载后立即使用库的功能
使用 Fetch 加载的场景:
需要检查或修改脚本内容
只在同源环境下使用
需要对加载过程有更精细的控制
4. 最佳实践
首选 Script 标签:对于大多数情况,特别是加载外部库,使用 Script 标签更可靠
添加超时处理:为脚本加载添加超时机制
提供备用方案:当主要 CDN 加载失败时,尝试备用源
检查已加载:避免重复加载同一脚本
5. 结论
在大多数情况下,使用 Script 标签加载外部 JS 文件是更可靠的选择,特别是当加载的脚本需要在全局作用域中注册函数或对象时。Fetch 方法虽然提供了更多的灵活性,但存在跨域限制和作用域问题,使用时需要格外小心。