重新溫習了下這段内容,發現各個浏覽器的相容性真的是搞大了頭,處理起來很是麻煩。
現在現總結下并行加載多個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')})