资讯专栏INFORMATION COLUMN

动态加载 js

jubincn / 2897人阅读

摘要:由于报表只有部分模块用到,所以想使用动态加载方式。常用的动态加载有两种。这里介绍动态创建标签的方法。不说了,直接上代码上面是动态加载的方法。当同时打开这些模块时,有可能会导致多次加载。所以可以把加载后的模块根据路径缓存起来。

前端项目中使用到了一个报表库 Plotly.js, 这个库有 600多k。由于报表只有部分模块用到,所以想使用动态加载方式。

首先想到使用 webpack 的懒加载,但是打包时间太长。加这个库之前 30秒,加之后 6 分钟。使用 noParse 也没有效果。

所以决定用到时,手动加载。

js 常用的动态加载有两种。ajax 加载后使用 eval 执行。或者使用 script 标签加载

这里介绍动态创建标签的方法。不说了,直接上代码:

// Attach handlers for all browsers


var loadScript = function (path, callback) {
    const me = this;
    const script = document.createElement("script");
    script.type = "text/javascript";
    let done = false;
    const head = document.head;
    const error = () => {
        if (!done) {
            done = true;
            script.onload = script.onreadystatechange = script.onerror = null;
            head.removeChild(script);
            callback(false);
        }
    }
    const success = () => {
        if (!done) {
            done = true;
            script.onload = script.onreadystatechange = script.onerror = null;
            head.removeChild(script);
            callback(true);
        }
    }
    script.onreadystatechange = function () {
        if (this.readyState == "loaded" || this.readyState == "complete") {
            success();
        }
    };
    script.onload = success;
    script.onerror = error;
    script.src = path;
    head.appendChild(script);
}

上面是动态加载 js 的方法。但是可能多个模块会用到这个 js 库。当同时打开这些模块时,有可能会导致多次加载。所以可以把加载后的模块根据路径缓存起来。

下面代码是使用 TypeScript 写的, 根据路径记录 js 文件加载信息,避免重复:

export default class LoadJs {

    public static loadSync(path: string): Promise {
        const me = this;
        return new Promise((resolve, reject) => {
            me.load(path, (bSuc) => {
                if (bSuc) {
                    resolve();
                } else {
                    reject();
                }
            });
        });
    }

    public static load(path: string, callback: (bSuc: boolean) => void): void {
        let lib = this.pathLoaded[path];
        // 没有记录,添加记录
        if (!lib) {
            lib = {
                isLoaded: false,
                callback: [callback],
            };
            this.pathLoaded[path] = lib;
        }
        // 已加载直接返回
        if (lib.isLoaded) {
            callback(true);
        } else {
            // 添加回调
            lib.callback.push(callback);
            // 加载
            const me = this;
            this.loadScript(path, suc => {
                if (suc) {
                    me.onLoad(lib, true);
                } else {
                    me.onLoad(lib, false);
                }
            })
        }
    }

    private static loadScript(path, callback) {
        const me = this;
        const script = document.createElement("script") as any;
        script.type = "text/javascript";
        let done = false;
        const head = document.head;
        const error = () => {
            if (!done) {
                done = true;
                script.onload = script.onreadystatechange = script.onerror = null;
                head.removeChild(script);
                callback(false);
            }
        }
        const success = () => {
            if (!done) {
                done = true;
                script.onload = script.onreadystatechange = script.onerror = null;
                head.removeChild(script);
                callback(true);
            }
        }
        script.onreadystatechange = function () {
            if (this.readyState == "loaded" || this.readyState == "complete") {
                success();
            }
        };
        script.onload = success;
        script.onerror = error;
        script.src = path;
        head.appendChild(script);
    }
    private static pathLoaded: { [key: string]: PathLoading } = {};
    private static onLoad(p: PathLoading, isSuc: boolean): void {
        p.isLoaded = true;
        for (const fun of p.callback) {
            fun(isSuc);
        }
        p.callback = [];
    }
}

interface PathLoading {
    isLoaded: boolean;
    callback: Array<(f: boolean) => void>;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89636.html

相关文章

  • js实用方法记录-js动态加载css、js脚本文件

    摘要:测试动态加载到标签并执行回调方法调用加载成功动态加载脚本地址回调函数加载样式站中下载打开方法测试页面跳转到微信中不能打开其他安卓手机尝试调用未指定需要打开的可参考自定义协议参数转换参考参数转对象使用对象转参数 js实用方法记录-动态加载css/js 1.动态加载js文件到head标签并执行回调方法调用:dynamicLoadJs(http://www.yimo.link/static/...

    shusen 评论0 收藏0
  • js实用方法记录-js动态加载css、js脚本文件

    摘要:测试动态加载到标签并执行回调方法调用加载成功动态加载脚本地址回调函数加载样式站中下载打开方法测试页面跳转到微信中不能打开其他安卓手机尝试调用未指定需要打开的可参考自定义协议参数转换参考参数转对象使用对象转参数 js实用方法记录-动态加载css/js 1.动态加载js文件到head标签并执行回调方法调用:dynamicLoadJs(http://www.yimo.link/static/...

    Dogee 评论0 收藏0
  • js实用方法记录-js动态加载css、js脚本文件

    摘要:测试动态加载到标签并执行回调方法调用加载成功动态加载脚本地址回调函数加载样式站中下载打开方法测试页面跳转到微信中不能打开其他安卓手机尝试调用未指定需要打开的可参考自定义协议参数转换参考参数转对象使用对象转参数 js实用方法记录-动态加载css/js 1.动态加载js文件到head标签并执行回调方法调用:dynamicLoadJs(http://www.yimo.link/static/...

    sanyang 评论0 收藏0
  • 原生JS动态加载JS、CSS文件及代码脚本

    摘要:属性共中状态初始状态加载中加载完成已加载并可与用户交互,但还需要加载图片等其他资源全部资源加载完成文档加载顺序解析结构加载外部脚本和样式表文件解析并执行脚本树构建完成加载外部资源文件图片等页面加载完成动态加载公共方法动态加载外部文件,并执行 DOM readyState属性共5中状态 uninitialized:初始状态 loading:document加载中 loaded: ...

    you_De 评论0 收藏0
  • 原生JS动态加载JS、CSS文件及代码脚本

    摘要:属性共中状态初始状态加载中加载完成已加载并可与用户交互,但还需要加载图片等其他资源全部资源加载完成文档加载顺序解析结构加载外部脚本和样式表文件解析并执行脚本树构建完成加载外部资源文件图片等页面加载完成动态加载公共方法动态加载外部文件,并执行 DOM readyState属性共5中状态 uninitialized:初始状态 loading:document加载中 loaded: ...

    yagami 评论0 收藏0

发表评论

0条评论

jubincn

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<