QQ群前端使用的 javascript loader
开始主要想看一下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); })(); |