在同域的情况下.无阻塞异步加载js的比较完美的方法就是通过XHR eval动态加载解析外部js文件.但XHR的问题就是.无法保证加载顺序.只是哪个.js文件先加载完毕就先执行哪个.所以我们需要用个队列机制将其管理.提供顺序引入的功能.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title> new document </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script>
if ( 'undefined' == typeof(System) || !System ) {
var System = {};
}
/**
* Xhr -- Eval -- Order
* xhr异步按顺序动态执行javascript
*/
System.Script = {
// 存放script请求队列
queuedScripts: new Array(),
/**
* 引入执行.js文件函数
* @param (String) url 要引入执行的.js文件路径
* @param (Function) onload 当引入.js文件执行完毕后执行的函数
* @param (Boolean) order 是否要按顺序引入
*/
load: function(url, onload, order) {
// 队列长度 数组形式(自动递增)
var iQueue = System.Script.queuedScripts.length;
// 如果引入的多个.js文件有依赖关系,那么我们需要order为true
if ( order ) {
// 维护js请求相对应的数组队列.并分别赋予一张默认的hash表
var qScript = { response: null, onload: onload, done: false };
System.Script.queuedScripts[iQueue] = qScript;
}
var xhrObj = this.getXHRObj();
xhrObj.onreadystatechange = function() {
// 获取xhr.并当xhr正确请求时
if ( xhrObj.readyState == 4 ) {
// 如果是有顺序的话.那么要讲所有的请求都按顺序放入到队列中.并将每次请求返回的js文本赋给response键值
if ( order ) {
System.Script.queuedScripts[iQueue].response = xhrObj.responseText;
// 紧接着开始按照队列顺序注入js
System.Script.injectScripts();
} else {
// 如果不需要按照顺序执行的话.那么就谁先加载完毕谁就直接通过Script.text去执行.执行完毕后.如果指定了onload则运行onload
var se = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(se);
se.text = xhrObj.responseText;
if ( onload ) {
onload();
}
}
}
};
xhrObj.open('GET', url, true);
xhrObj.send('');
},
/**
* 获取Xhr
*/
getXHRObj: function() {
var methods = [
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject('Xml2.XMLHTTP'); },
function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
];
for ( var i = 0, len = methods.length; i < len; i++ ) {
try {
methods[i]();
this.getXHRObj = methods[i];
break;
} catch(e) {}
}
return methods[i]();
},
/**
* 用于按顺序引用JS.从队列中顺序注入javascript
*/
injectScripts: function() {
// 开始循环注入js
var len = System.Script.queuedScripts.length;
for ( var i = 0; i < len; i++ ) {
var qScript = System.Script.queuedScripts[i];
if ( !qScript.done ) {
// 如果有一个script请求没有返回.那么就中断.
if ( !qScript.response ) {
break;
} else {
var se = document.createElement('script');
document.getElementsByTagName('head')[0].appendChild(se);
se.text = qScript.response;
if ( qScript.onload ) {
qScript.onload();
}
qScript.done = true;
}
}
}
}
};
function init() {
document.title += 'init function';
}
System.Script.load('main.js', null, true);
System.Script.load('sub.js', init, true);
</script>
</body>
</html>
上面的代码就是一个具有队列性质的管理机制.
用法就是:
System.Script.load('main.js', null, true);
System.Script.load('sub.js', init, true);
表示引入两个.js文件.顺序为先main.js然后再sub.js并且当sub.js执行完毕后会调用init方法.