首页 > 代码库 > 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>‘)的方式来并行加载(IE8以及以上,现代浏览器)和顺序执行。

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

      4,<script>的type属性设为”script/cache” 非标准的type属性,使js文件只会被加载而不会执行。需要执行时,创建一个type

    属性为”text/javascript”的正常<script>元素,src设为前面已经加载的js地址即可,执行顺序开发者可控(执行时机也完全

    可控)。类似的方式也有通过<img>来做预加载的。

 

已经有些大牛比如之前提到的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="http://www.mamicode.com/‘ +                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;            }            loadMethod = asyncHelper._loadJsWithDOMElement;            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‘)})

 

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