开始主要想看一下qq群所使用的javascript模板,后来发现他们用的也是一个jquery的插件。
不过这个加载写的也很不错,分析了一下,原JS: http://qun.qq.com/god/m/js/loader.zh-cn.js
; (function() {
var window = this,
undefined,
jLoader = window.jLoader = window.jL = {
_version: "1.2.1",
_sequence: [],
_queue: {},
_xhr: function() {
return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
},
// 直接加载脚本
_script: function(uri, context) {
context = context || document;
var head = context.getElementsByTagName("head")[0] || context.documentElement,
script = context.createElement("script");
script.type = "text/javascript";
script.src = uri;
head.appendChild(script);
return script;
},
_style: function(uri, context) {
context = context || document;
var head = context.getElementsByTagName("head")[0] || context.documentElement,
link = context.createElement("link"),
links = context.getElementsByTagName("link", context);
link.type = "text/css";
link.rel = "stylesheet";
link.href = uri;
if (0 < links.length) {
var _last = links[links.length - 1];
_last.parentNode.insertBefore(_link, _last.nextSibling);
} else {
head.appendChild(link);
}
return link;
},
_replace: function(pattern, uri, context) {
if (!pattern || !uri) {
return;
}
context = context || document;
var links = context.getElementsByTagName("link", context);
for (var i = links.length - 1; i >= 0; i--) {
if ( - 1 != links[i].href.indexOf(pattern)) {
links[i].parentNode.removeChild(links[i]);
}
}
if (uri) {
jLoader._style(uri, context);
}
},
// 将脚本内容插入当前页面来执行
_globalEval: function(data, context) {
if (data && /\S/.test(data)) {
context = context || document;
var head = context.getElementsByTagName("head")[0] || context.documentElement,
script = context.createElement("script");
script.type = "text/javascript";
if (jLoader._excute) {
script.appendChild(context.createTextNode(data));
} else {
script.text = data;
}
head.insertBefore(script, head.firstChild);
head.removeChild(script);
return true;
}
return false;
},
// 执行回调方法数组。有可能请求多次,绑定了多个的回调方法。
_call: function(mark) {
if (jLoader._queue[mark].callbacks) {
var cl = jLoader._queue[mark].callbacks.length;
for (var j = 0; j < cl; j++) {
jLoader._queue[mark].callbacks[j][0](jLoader._queue[mark].callbacks[j][1]);
}
}
},
// 这是一个顺序加载的过程,每加载一个JS,都会放入sequence队列,如果depend=true,则该脚本之前的脚本全部加载完后该脚本才执行
_inject: function() {
var len = jLoader._sequence.length;
for (var i = 0; i < len; i++) {
var seq = jLoader._queue[jLoader._sequence[i]];
if (!seq.done) {
if (!seq.response) {
return;
} else {
seq.done = true;
seq.response = [seq.response, ";jLoader._call(\"", jLoader._sequence[i], "\");"].join("");
jLoader._globalEval(seq.response);
}
}
}
},
scripted: function(mark) {
if ("undefined" == typeof jLoader._queue[mark]) {
return false;
} else {
if (jLoader._queue[mark].done) {
return true;
} else {
return false;
}
}
},
script: function(options) {
options = options || {};
// 参数不全
if (!options.mark || !options.uri)
return;
options.depend = options.depend || false;
options.params = options.params || {};
options.onload = options.onload || null;
// 如果没有依赖关系和回调方法,则直接引入
if (!options.onload && !options.depend) {
jLoader._script(options.uri);
jLoader._queue[options.mark] = {
uri: options.uri,
response: null,
done: true
};
return;
}
// 是否为第一次请求
if ("undefined" == typeof jLoader._queue[options.mark]) {
jLoader._queue[options.mark] = {
uri: options.uri,
response: null,
done: false
};
// 设置回调方法和回调的参数
if ("function" == typeof options.onload) {
jLoader._queue[options.mark].callbacks = [[options.onload, options.params]];
}
} else {
// 虽然不是第一次请求,但有没有真正加载。没有真正加载的原因此时正在异步请求脚本内容
if (false == jLoader._queue[options.mark].done) {
// 如果已经设置为callbacks, 则追加callbacks, 前面设置的callbacks是数组
if ("function" == typeof options.onload) {
if ("undefined" == typeof jLoader._queue[options.mark].callbacks) {
jLoader._queue[options.mark].callbacks = [[options.onload, options.params]];
} else {
var cl = jLoader._queue[options.mark].callbacks.length;
jLoader._queue[options.mark].callbacks[cl] = [options.onload, options.params];
}
}
} else {
// 已真正加载,直接执行回调方法
if ("function" == typeof options.onload) {
options.onload(options.params);
}
}
return;
}
// 将脚本按顺序放入队列,self._inject会用到
var len = jLoader._sequence.length;
if (options.depend) {
jLoader._sequence[len] = options.mark;
}
var xhr = jLoader._xhr();
xhr.onreadystatechange = function() {
if (4 == xhr.readyState) {
// 如果设置了依赖关系,则检查依赖。如果没有设置,则执行脚本内容和回调函数
if (options.depend) {
jLoader._queue[options.mark].response = xhr.responseText;
jLoader._inject();
} else {
jLoader._queue[options.mark].done = true;
var response = [xhr.responseText, ";jLoader._call(\"", options.mark, "\");"].join("");
jLoader._globalEval(response);
}
}
};
xhr.open("GET", options.uri, true);
xhr.send("");
}
};
// 很好,很强大,因为getTime()结果不一样,所以用这种方法可以准确的定位到某一个类有没有执行
jLoader._excute = false;
var root = document.documentElement,
script = document.createElement("script"),
id = "script" + (new Date).getTime();
script.type = "text/javascript";
try {
script.appendChild(document.createTextNode("window." + id + "=1;"));
} catch(e) {}
root.insertBefore(script, root.firstChild);
if (window[id]) {
jLoader._excute = true;
delete window[id];
}
root.removeChild(script);
})();