这篇文章也可以在我的博客中阅读。
关于本文
- 介绍非模块脚本(传统脚本)使用JavaScript动态载入的方法
概要
目前有许多动态按需载入JavaScript模块的方法,比如import和require,但许多老旧的JavaScript脚本由于涉及到全局变量的操作,不支持以模块的形式载入(会出现各种错误),如果需要在代码中动态载入某些老旧的非模块脚本,这个脚本可以助你一臂之力。
脚本特点
优点
- 简短
- 不需要安装第三方库
- 兼容现阶段所有浏览器(除IE)
- 异步加载
- 支持多个备用链接(用途:CDN炸了可以回退到本地)
缺点
- 不具备依赖项加载功能
- 不检测加载的内容到底是不是JavaScript(错误的内容返回200也会被当做JavaScript)
脚本
主要是动态组织script元素,其中使用Promise对加载结果进行跟踪。
function jsLoader(urls, async = true, type = "text/javascript") {
var load = (url) => {
return () => new Promise((resolve, reject) => {
const scriptEle = document.createElement("script");
try {
scriptEle.type = type;
scriptEle.async = async;
scriptEle.src = url;
scriptEle.addEventListener("load", () => resolve());
scriptEle.addEventListener("error", () => { console.log("fallback to next src..."); rejectHandler(); });
document.body.appendChild(scriptEle);
} catch (error) {
rejectHandler(error);
}
var rejectHandler = (e) => {
document.body.removeChild(scriptEle);
reject(e);
}
});
};
return urls.reduce((p, url) => p.catch(load(url)), Promise.reject()).catch((e) => { console.log("oops, all src failed"); throw e; });
}
用法
示意
- 传入存放备选src的数组(这里选的第1,2,4个链接都是无效的)
- 可使用Promise语法对脚本进行控制
urls = ["https://wrong.page", "2", "https://cdn.jsdelivr.net/npm/activate-power-mode@1.0.0/dist/activate-pow1er-mode.min.js", "4"]
jsLoader(urls)
.then(() => console.log("module loaded")) //加载成功
.catch(() => { }); //出错
输出
- 成功载入后,后面的链接不会再继续载入
- 失败时会有log输出,不需要的可以注释掉
GET https://wrong.page/ net::ERR_CONNECTION_CLOSED
fallback to next src...
GET file:///H:/test/2 net::ERR_FILE_NOT_FOUND
fallback to next src...
module loaded