原生JS实现动态批量加载js文件


有的时候需要动态加载javascript文件,并且在加载成功后执行回调函数。要实现这样的功能,可以使用<script> 元素的load事件(IE9+、chrome、FireFox等)和onreadystatechange 事件(IE8以下)

当你只需要加载一个js文件时,可以使用这段代码:

function loadScript(src, callback) {
    var script = document.createElement('script'),
        head = document.getElementsByTagName('head')[0];
    script.type = 'text/javascript';
    script.charset = 'UTF-8';
    script.src = src;
    if (script.addEventListener) {
        script.addEventListener('load', function () {
            callback();
        }, false);
    } else if (script.attachEvent) {
        script.attachEvent('onreadystatechange', function () {
            var target = window.event.srcElement;
            if (target.readyState == 'loaded') {
                callback();
            }
        });
    }
    head.appendChild(script);
}

//调用
loadScript('http://cdn.staticfile.org/jquery/1.6.2/jquery.min.js',function(){
    console.log('onload');
});

当你需要加载多个js文件时:

function loadScript(src, callback) {
    arraySync(function (one, i, c) {
        var cur_script = document.createElement("script");
        cur_script.type = 'text/javascript';
        cur_script.charset = 'UTF-8';
        cur_script.src = one;
        cur_script.addEventListener('load', function () {
            c(0, {
                i: i,
                v: {}
            });
        }, false);
        document.head.appendChild(cur_script)
    }, src, function (err, r) {
        //全部加载完成后执行的回调函数
        if (err) {
            dhtmlxAlert(err.message);
        } else {
            callback()
        }
    });
}

//处理异步,不用promise的方案
function arraySync(bsFunc, ar) {
    var callback = arguments[arguments.length - 1];
    if (ar.length == 0) {
        callback(0, []);
        return;
    }
    var sendErr = false;
    var finishNum = ar.length;
    var result = [];
    var args = [0, 0];
    for (var index = 2; index < arguments.length - 1; ++index) {
        args.push(arguments[index]);
    }
    args.push(function (err, r) {
        if (err) {
            if (!sendErr) {
                sendErr = true;
                callback(err);
            }
            return;
        }
        --finishNum;
        result[r.i] = r.v;
        if (finishNum == 0) {
            callback(0, result);
        }
    });

    for (var i = 0; i < ar.length; ++i) {
        args[0] = ar[i];
        args[1] = i;
        bsFunc.apply(null, args);
    }
};

//调用
loadScript(['./jquery.min.js','./echarts.min.js','./vue.min.js'],function(){
    console.log('onload');
});

上述代码使用了arraySync方案来处理异步,如果条件允许,你也可以使用promise来解决,效果都是一样的。

我的项目中是需要从json文件中读取配置,取到的数据中有需要动态加载的js列表,然后使用上述的批量加载js函数进行处理,下面给出整体代码,有需要的可以搭配使用哦~

var loadScript = function (callback) {
    //读取json
    var request = new XMLHttpRequest();
    request.open("get", "package.json");
    request.send(null);
    request.onload = function () {
        if (request.status == 200) {
            var package = JSON.parse(request.responseText);
            //合并dependencies和plugins对象
            Object.assign(package.dependencies, package.plugins);
            var scriptUrls = [];
            for (var i in package.dependencies) {
                scriptUrls.push(package.dependencies[i])
            }
            //异步载入script
            arraySync(function (one, i, c) {
                var cur_script = document.createElement("script");
                cur_script.type = 'text/javascript';
                cur_script.charset = 'UTF-8';
                cur_script.src = one;
                cur_script.addEventListener('load', function () {
                    c(0, {
                        i: i,
                        v: {}
                    });
                }, false);
                document.head.appendChild(cur_script)
            }, scriptUrls, function (err, r) {
                if (err) {
                    dhtmlxAlert(err.message);
                } else {
                    callback()
                }
            });
        }
    }
}

//处理异步,不用promise的方案
function arraySync(bsFunc, ar) {
    var callback = arguments[arguments.length - 1];
    if (ar.length == 0) {
        callback(0, []);
        return;
    }
    var sendErr = false;
    var finishNum = ar.length;
    var result = [];
    var args = [0, 0];
    for (var index = 2; index < arguments.length - 1; ++index) {
        args.push(arguments[index]);
    }
    args.push(function (err, r) {
        if (err) {
            if (!sendErr) {
                sendErr = true;
                callback(err);
            }
            return;
        }
        --finishNum;
        result[r.i] = r.v;
        if (finishNum == 0) {
            callback(0, result);
        }
    });

    for (var i = 0; i < ar.length; ++i) {
        args[0] = ar[i];
        args[1] = i;
        bsFunc.apply(null, args);
    }
};
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,161评论 1 32
  • # 模块机制 node采用模块化结构,按照CommonJS规范定义和使用模块,模块与文件是一一对应关系,即加载一个...
    RichRand阅读 2,568评论 0 3
  • 你不知道JS:异步 第三章:Promises 在第二章,我们指出了采用回调来表达异步和管理并发时的两种主要不足:缺...
    purple_force阅读 2,126评论 0 4
  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 2,753评论 0 5
  • 上一章介绍了模块的语法,本章介绍如何在浏览器和 Node 之中加载 ES6 模块,以及实际开发中经常遇到的一些问题...
    emmet7life阅读 2,820评论 0 1