专栏首页前端杂货铺js的并行加载以及顺序执行

js的并行加载以及顺序执行

重新温习了下这段内容,发现各个浏览器的兼容性真的是搞大了头,处理起来很是麻烦。

现在现总结下并行加载多个js的方法:

  1,对于动态createElement('script')的方式,对所有浏览器都是异步并行加载的。这里所说的并行不仅仅指的是

    js并行加载,也包括js和其他资源比如图片,iframe的加载。但是此种方式在Firefox的2.0 3.0 3.1版本和opera 9.63

    下是可以顺序执行的。但是由于Kyle的提议,现代浏览器都可以通过对动态创建的script元素设置属性async=false来使

    js顺序执行。

  2,可以通过document.write('<script>')的方式来并行加载(IE,现代浏览器)和顺序执行。

  3,通过xhr加载js。但是有了同源的限制,因此对于外部js文件或者cdn上的js就无能为力。

已经有些大牛比如之前提到的Kyle已经提供了兼容个浏览器的标准库,项目名称是 LABjs

自己写了一个简单的插件,目前并没有在IE6,7上测试。

        if(!asyncHelper) var asyncHelper = {};
        asyncHelper.cache = []; //存储获取到的js对象

        asyncHelper.createAjax = (function(){
            if('XMLHttpRequest' in window){
                return function(){
                    return new XMLHttpRequest();
                }
            }else{
                var i= 0,len, fns = [function(){return new ActiveXObject('Microsoft.XMLHTTP')},function(){return new ActiveXObject('Msxml2.XMLHTTP')},
                    function(){return new ActiveXObject('Msxml2.XMLHTTP.3.0')},function(){return new ActiveXObject('Msxml2.XMLHTTP.6.0')}];

                for(len = fns.length;i<len;i++){
                    try{
                        fns[i]();
                        return fns[i];
                        break;
                    }catch (e){
                    }
                }
            }
        })();
        //功能函数,异步xhr加载js,并行无序加载js和其他资源,需要进行顺序控制;而且受同源限制,
        //无法使用cdn或外部引用js
        asyncHelper._loadJsWithXHR = function(url,fn,inOrder){
            inOrder = inOrder || true; //默认顺序加载
            var jsObj = {file: null,isLoaded:false,callback: fn},xhr,
                    i,len;
            asyncHelper.cache.push(jsObj);
            xhr = this.createAjax();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    try{
                        if(xhr.status >=200 && xhr.status < 300 || xhr.status == 304){
                            jsObj.file = xhr.responseText; // 返回的js存入对象中
                            if(inOrder){
                                for(i=0,len=asyncHelper.cache.length;i<len;i++){
                                    if(!asyncHelper.cache[i].file){
                                        //避免重复解析已加载过得js文件
                                        //从缓冲汇总删除已经加载的文件
                                        if(i>0){
                                            asyncHelper.cache.splice(0,i);
                                        }
                                        break;
                                    }else{
                                        //Function相当于全局eval,不会改变作用域链
                                        new Function(asyncHelper.cache[i].file)();
                                        fn && fn(); //执行回调函数
                                        if(i == len-1){
                                            asyncHelper.cache = []; //清空缓存
                                        }
                                    }
                                }
                            }else{
                                if(jsObj.file){
                                    eval(jsObj.file);
                                    fn();
                                }
                            }
                        }
                    }catch (loadError){
                        setTimeout(function(){
                            throw(new Error('loading with XHR response error--' + loadError))
                        },0);
                    }

                }
            };
            xhr.open('get',url);
            xhr.setRequestHeader('X-Request-With','XMLHttpRequest');
            xhr.send(null);
        };

        //通过创建script元素来异步加载js,支持跨域。在firefox,opera下也是顺序加载。
        asyncHelper._loadJsWithDOMElement = function(url,fn){
            var dom = document.createElement('script');
            dom.type = 'application/javascript';
            dom.async = false;
            dom.src = url;
            dom.isloaded = false;
            //执行回调函数,IE下使用onreadystatechange,w3c使用onload
            if('onload' in dom){
                dom.onload = fn;
            }else{
                dom.onreadystatechange = function(){
                    if((dom.readyState == 'loaded' || dom.readyState == 'complete') &&
                            !dom.isloaded){
                        fn();
                        dom.isloaded = true;
                    }
                }
            }
            document.getElementsByTagName('head')[0].appendChild(dom);
        }

        //通过document.write插入script来进行并行加载脚本。gte IE8以及opera支持。
        //全部浏览器支持此种方式的顺序加载js
        asyncHelper._loadJsWithScriptTag = function(url,fn){
            document.writeln('<script type="application/javascript" src="' +
                url +'"><\/script>');
            //给window绑定onload事件
            if(window.addEventListener){
                window.addEventListener('load',fn,false);
            }else{
                window.attachEvent('onload',function(){
                    fn.call(this,window.event);
                })
            }
        }

        //暴露外部接口,加载单个js文件
        asyncHelper.loadScript = function(url,fn){
            this._loadJsWithDOMElement(url,fn);
        }

        //加载多个js文件
        asyncHelper.loadScripts = function(urls,fn){
            function isSameDomain(url){
                var domain = document.location.protocol + "//" +
                        document.location.hostname + "/";
                if(url.indexOf('http') !== -1 || url.indexOf('https') !== -1){
                    if(url.indexOf(domain) !== -1){
                        return true;
                    }
                    return false;
                }
                return true;
            }

            //如果url同源,则使用xhr加载
            var i,len,flag,loadMethod;
            for(i=0,len=urls.length;i<len;i++){
                if(flag = isSameDomain(urls[i])) continue;
                else break;
            }
            //默认xhr加载
            loadMethod = asyncHelper._loadJsWithXHR;
            if(!flag){
                //firefox opera使用DomElement方式加载,确保顺序性和异步加载
                // 经测试,目前最新版本的Firefox亦不支持此特性。
                //Firefox 4为了更向HTML5标准看齐,一度在开发者版本中去掉了对动态创建<script>来加载js文件的执行顺序支持:
                //<script> elements created using document.createElement() and inserted into a document now behave
                // according to the HTML5 specification by default. Scripts with the src attribute
                // execute as soon as available (without maintaining ordering) and scripts without
                // the src attribute execute synchronously.

                //Kyle向WebKit开发团队抗议,提了一个bug,最终得到了如他所愿的支持:
                //To make script-inserted scripts that have the src attribute execute in the insertion order,
                // set .async=false on them.
                if(navigator.userAgent.toLowerCase().indexOf('firefox') != -1 || navigator.userAgent.toLowerCase().indexOf('opera') != -1)
                    loadMethod = asyncHelper._loadJsWithDOMElement;
                else
                    loadMethod = asyncHelper._loadJsWithScriptTag;

            }for(i=0;i<len;i++){
                if(i == len - 1){
                    loadMethod.call(asyncHelper,urls[i],fn);
                }else{
                    loadMethod.call(asyncHelper,urls[i]);
                }
            }
        }

// 示例代码  
asyncHelper.loadScripts(['http://libs.baidu.com/jquery/1.9.0/jquery.js','./a.js','./b.js'],function(){console.log('success')})

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • iOS引入JavaScriptCore引擎框架(一)

    JavaScriptCore引擎     我们都知道WebKit是个渲染引擎,简单来说负责页面的布局,绘制以及层的合成,但是WebKit工程中不仅仅有关于渲染相...

    欲休
  • iOS引入JavaScriptCore引擎框架(二)

    为何放弃第一种方案 UIWebView的JSContext获取     上篇中,我们通过简单的kvc获取UIWebVIew的JSContext,但是实际上,ap...

    欲休
  • 自动补全搜索实现

    目前大多数搜索框都已实现自动补全功能,自己也私底下实现了一个简易版本, 在此总结过程中的一些要点:   1,侦听文本框的value值改变,注意在Ie8及其之前版...

    欲休
  • CS系列-Socks代理应用

    例如拿下了一台主机,该主机存在dmz区,有公网ip,可以访问内网,那么我们需要借助这个主机为跳板来进行后续的内网渗透。

    字节脉搏实验室
  • JAVASCRIPT FUNCTIONS 详解

    本文是@堂主 对《Pro JavaScript with Mootools》一书的第二章函数部分知识点讲解的翻译。该书的作者 Mark Joseph Obcen...

    政采云前端团队
  • c++11:如何判断std::function对象相同?

    我们知道std::function的实质就是个函数指针,但在c++11中std::function并没有实现操作符==(要到C++20才实现),所以我们无法使用...

    用户1148648
  • 「小程序JAVA实战」 小程序私有页面的生命周期以及导航(10)

    PS:这块主要是对配置的生命周期的熟悉,了解下redirectTo 和 navigateTo 之前的区别。

    IT故事会
  • Product Archive相关的标准function module

    版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)

    Jerry Wang
  • 再谈Android动态链接库

    前不久,我们准备将自己开发的视频播放sdk提供给公司其他部门,在打包的时候,同事问了我一个问题,为什么我们打sdk的时候需要分别提供armeabi和arm64-...

    xiangzhihong
  • 电能质量监测方案

    用物联网+腾讯云平台结合无功补偿、电能质量设备将电能质量监测数据实时传送给需要的工作人员,工作人员可以根据数据 进行分析,然后做出合理的处理方式,为电能质量监测...

    用户7003292

扫码关注云+社区

领取腾讯云代金券