动态加载 script 的兼容核心是按浏览器能力分支:ie 系列(含 ie9+)用 onreadystatechange 并清空 handler,其他浏览器用 onload;css 加载则不可套用该模式,需轮询或规则检测。

动态创建 <script></script> 标签并监听加载完成,核心难点在于 IE 低版本不支持 onload 事件,而现代浏览器又普遍支持;IE9+ 则两者都支持,容易导致回调执行两次。兼容写法的关键是:**按浏览器能力分支处理,且避免重复绑定**。
区分 IE 与非 IE 的基本判断逻辑
不能只靠 UA 字符串,更可靠的是检测 DOM 元素是否具备 readyState 属性:
- 若
script.readyState !== undefined→ 视为 IE(含 IE6–11)或旧版 Opera - 否则 → 使用
onload(Firefox、Chrome、Safari、Edge、现代 Opera)
注意:IE9/10/11 同时支持 onload 和 onreadystatechange,所以必须只启用其中一个分支,不能共存。
安全的 onload 回调绑定方式
推荐显式分离两个事件处理器,避免用同一函数同时赋给 onload 和 onreadystatechange:
- 对 IE 系列:仅设
onreadystatechange,并在回调中立即清空该 handler,防止重复触发 - 对其他浏览器:只设
onload,不碰onreadystatechange - 务必监听
onerror,捕获 404 或跨域失败等异常
示例片段:
function loadScript(url, callback) {
const script = document.createElement('script');
script.src = url;
if ('onload' in script) {
script.onload = () => {
callback();
script.onload = null;
};
} else {
script.onreadystatechange = function() {
if (this.readyState === 'loaded' || this.readyState === 'complete') {
callback();
this.onreadystatechange = null;
}
};
}
script.onerror = () => {
console.error(`Failed to load script: ${url}`);
};
document.head.appendChild(script);
}
现代项目建议:用 Promise 封装 + async/await
如果目标环境支持 ES6+,直接返回 Promise 更清晰、易组合:
- 默认使用
onload,绝大多数场景已足够 - 仍需保留
onerror拒绝 Promise,避免静默失败 - 无需主动兼容 IE6–8(2026 年已基本淘汰),但若需支持 IE9/10,上述 Promise 版本依然安全(它们支持
onload)
简洁实现:
function loadScript(url) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = url;
s.onload = () => resolve();
s.onerror = () => reject(new Error(`Script load failed: ${url}`));
document.head.appendChild(s);
});
}
// 使用
loadScript('/js/chart.js')
.then(() => initChart())
.catch(err => console.warn(err));
特别注意 CSS 动态加载的差异
<link rel="stylesheet"> 的 onload 兼容性更差:
- Firefox 和 Safari 从不触发
onload - Chrome、Edge、IE 支持,但行为不一致
- 稳妥做法:用定时轮询
document.styleSheets或插入后检查特定 CSS 规则是否生效
因此,动态加载 CSS 不应套用 script 的 onload 模式,需单独处理。











