异步加载网络js脚本并返回Promise

手写实现从网络异步加载js脚本,并返回Promise实例,如果加载成功就执行resolve,失败或超时就执行reject。

/**
 * 异步加载函数
 * @param src 脚本 url 地址
 * @param delay 加载的最大允许时间
 */
function asyncLoad(src, delay) {
    return new Promise((resolve, reject) => {
        // 创建一个 script 元素
        const script = document.createElement('script');
        // type 属性也可以不设置
        script.type = 'text/javascript';
        // 指定 src 的值
        script.src = src;
        // 将元素添加进 DOM 文档
        document.body.appendChild(script);

        const ERROR_STR = '加载失败';

        // 设置超时函数
        const timer = setTimeout(() => {
            reject(ERROR_STR);
        }, delay);

        // 设置监听状态的回调函数
        if (script.readyState) {  // IE
            script.onreadstatechange = function() {
                // 取消计时函数
                clearTimeout(timer);
                if (['loaded', 'complete'].includes(script.readyState)) {
                    script.onreadstatechange = null;
                    resolve();
                } else {  // 加载失败的情况
                    reject(ERROR_STR);
                }
            }
        } else {  // Chrome、Edge、Safari、Firefox 等
            script.onload = function() {
                clearTimeout(timer);
                resolve();
            }
        }
    });
}

// 测试代码
const src = 'http://libs.baidu.com/jquery/2.0.0/jquery.min.js';
const start = Date.now();
asyncLoad(src, 5000).then(() => {
    // 此时 jQuery 已经加载,可以使用 $ 来选择元素
    $('#app')[0].textContent = `加载完毕,耗时:${Date.now() - start} ms`;
}).catch(err => {
    const app = document.getElementById('app');
    app.textContent = err;
});

版权

本作品采用 CC BY-NC-ND 4.0 授权。