关于本文
- 介绍非模块脚本(传统脚本)使用JavaScript动态载入的方法
 
概要
目前有许多动态按需载入JavaScript模块的方法,比如import和require,但许多老旧的JavaScript脚本由于涉及到全局变量的操作,不支持以模块的形式载入(会出现各种错误),如果需要在代码中动态载入某些老旧的非模块脚本,这个脚本可以助你一臂之力。
脚本特点
优点
- 简短
 - 不需要安装第三方库
 - 兼容现阶段所有浏览器(除IE)
 - 异步加载
 - 支持多个备用链接(用途:CDN炸了可以回退到本地)
 
缺点
- 不具备依赖项加载功能
 - 不检测加载的内容到底是不是JavaScript(错误的内容返回200也会被当做JavaScript)
 
脚本
主要是动态组织script元素,其中使用Promise对加载结果进行跟踪。
/**
 * dynamically load javascript.
 * fallback if former one fails.
 * promise supported.
 * @param {*} urls source array in priority
 * @param {boolean} async
 * @param {string} type 
 * @returns Promise object
 */
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/[email protected]/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