为了提升页面的打开和加载速度,咱们常常把JS文件放在页面的尾部,可是有些JS必须放在页面前面,这样就会增长页面的加载时间;因而出现了按需动态加载的概念,这个概念就是当页面须要用到这个JS文件或者CSS渲染文件的时候,在去请求这些文件,这样就节省了页面的加载时间javascript
LABjs 是一个很小的 JavaScript 工具,用来根据须要加载 JavaScript 文件,经过使用该工具能够提高页面的性能,避免加载不需用到的 JavaScript 文件,能够实现动态并行加载脚本文件,以及管理加载脚本文件的执行顺序。html
简单示例html5
$LAB .script("script1.js", "script2.js", "script3.js") .block(function(){ // wait for all to load, then do something script1Func(); script2Func(); script3Func(); });
介绍下LABJS的几个实例:java
实例1:ajax
$LAB .script("script1.js") .script("script2.js") .script("script3.js") .wait(function(){ // 等待全部script加载完再执行这个代码块 script1Func(); script2Func(); script3Func(); });
实例2:chrome
$LAB .script({ src: "script1.js", type: "text/javascript" }) .script("script2.js") .script("script3.js") .wait(function(){ // 等待全部script加载完再执行这个代码块 script1Func(); script2Func(); script3Func(); });
实例3:跨域
$LAB .script("script1.js", "script2.js", "script3.js") .wait(function(){ // 等待全部script加载完再执行这个代码块 script1Func(); script2Func(); script3Func(); });
实例4:浏览器
$LAB .script( [ "script1.js", "script2.js" ], "script3.js") .wait(function(){ // 等待全部script加载完再执行这个代码块 script1Func(); script2Func(); script3Func(); });
实例5:缓存
$LAB .script("script1.js").wait() // 空的wait()只是确保script1在其余代码以前被执行 .script("script2.js") // script2 和 script3 依赖于 script1 .script("script3.js").wait() // 可是script2 和 script3 并不互相依赖,能够并行下载 .script("script4.js") // script4 依赖于 script1, script2 及 script3 .wait(function(){script4Func();});
实例6:async
$LAB .script("script1.js") // script1, script2, and script3 之间没有依赖关系, .script("script2.js") // 因此能够任意顺序执行 .script("script3.js") .wait(function(){ // 若是须要,这里固然能够执行javascript函数 alert("Scripts 1-3 are loaded!"); }) .script("script4.js") // 依赖于 script1, script2 及 script3 .wait(function(){script4Func();});
实例7:
$LAB .setOptions({AlwaysPreserveOrder:true}) // 设置每一个脚本之间等待 .script("script1.js") // script1, script2, script3, script4 互相依赖 .script("script2.js") // 而且并行下载后循序执行 .script("script3.js") .script("script4.js") .wait(function(){script4Func();});
实例8:
$LAB .script(function(){ // `_is_IE`的值ie为true ,非ie为false if (_is_IE) { return "ie.js"; // 若是是ie则这个js会被加载 } else { return null; //若是不是ie这个代码就会被略过 } }) .script("script1.js") .wait();
LABjs加载方式
LABjs里的动态加载脚本文件,是指页面的js脚本执行时,经过多种方法去加载外部的js(主要区别于html页面里,经过<script>标签静态加载的脚本)
动态加载脚本的方式有不少,优缺点不一,此处不赘述,有兴趣的童鞋能够参见本文末尾的参考连接 :)。
LABjs里主要使用了三种技巧,分别为Script Element、XHR Injection以及Cache Trick
首先对这三种加载方式进行简单介绍,第四部分再分析LABjs源码实现里面对着三种方式分别的使用场景
Script Element(LABjs默认采用加载方式)
最多见的脚本动态加载方式,优势不少,包括:一、实现简单 二、可跨域 三、不会阻塞其余资源的加载 等
Opera/Firefox(老版本)下:脚本执行的顺序与节点被插入页面的顺序一致
IE/Safari/Chrome下:执行顺序没法获得保证
注意:
新版本的Firefox下,脚本执行的顺序与插入页面的顺序不必定一致,但可经过将script标签的async属性设置为false来保证顺序执行
老版本的Chrome下,脚本执行的顺序与插入页面的顺序不必定一致,但可经过将script标签的async属性设置为false来保证顺序执行
XHR Injection
经过ajax请求加载脚本文件,而后再经过如下方式执行:
eval:常见方式
XHR injection:建立一个script元素,并将请加载的脚本文件的内容注入
主要限制:没法跨域
Cache Trick(强依赖于浏览器的特性实现,不推荐使用)
当你将script元素的type属性设置为浏览器不认识的值,好比”text/cache”、”text/casper”、”text/hellworld”等,不一样浏览器的行为以下:
IE/Safari/Chrome(老版本)里:脚本照常加载,但不会执行,假设浏览器没有禁用缓存,加载后的脚本会被浏览器缓存起来,当须要用到 的时候,只须要从新建立个script标签,将type设为正确的值,src指向以前请求的文件url便可(至关于从缓存里读文件)
Opera/Firefox:不加载
备注:
强依赖于浏览器的特性实现,有可能随着浏览器特性实现的改变而失效,不推荐使用
新版本的chrome浏览器,将script元素的type设置为非”text/javascript”,不会再对脚本文件进行加载。
LABjs里关于脚本加载采用方案的判断
忽略技术细节,经过一段伪代码来描述LABjs里面的实现,大体为:
首先判断是否对请求的脚本进行预加载(是否进行预加载的判断条件看伪代码注释);
如进行预加载,再判断浏览器是否支持真正的预加载;如支持真正的预加载,则预加载之;如否,判断请求的脚本是否跟当前页面同域,如实,采用XHR Injection,如否,采用Cache Trick;
如不进行预加载,判断浏览器支不支持script元素的async属性(见伪代码注释),如是,设置async属性,并请求脚本文件;如否,直接经过script元素加载脚本文件;
if(ifPreloadScript){ //当请求的脚本文件是否进行预加载:一、须要预加载 二、浏览器支持预加载 if(supportRealPreloading){ //若是支持真正的预加载 if(supportPreloadPropNatively){ //支持经过设置script标签的preload属性,实现script的预加载,以及分离加载和执行 //Nicholas C. Zakas大神的美好愿望,还没有有浏览器支持:/blog/2011/02/14/separating-javascript-download-and-execution/ script.onpreload = callback; script.newPreload = true; script.src = targetUrl; }else{ script.onreadystatechange = callback; //其实就是指IE浏览器,假设指定了script元素的src属性,IE浏览器里会当即加载 script.src = targetUrl; //即便script元素没有被插入页面,callback为预加载后的回调 } } else if(inSameDomain){ //非跨域,采用XHR Injection:请求的脚本与当前页面处于同一个域 xhr = new XMLHttpRequest(); //因为上个判断已经将IE无情地抛弃在这个条件分支以外,因此大胆地用 new XMLHttpRequest()吧 xhr.onreadystatechange = callback; xhr.open("GET",targetUrl); xhr.send(); } else{ //最无奈的后招,Cache Trick,新版chromei已经不支持 script.onload = callback; script.type = 'text/cache'; script.src = targetUrl; } }else{ if(canContrlExecutionOrderByAsync){ //若是可以经过script元素的async属性来强制并行加载的脚本顺序执行 //kyle大神着力推动的提案,目前已被html5小组接受并放入草案:/Dynamic_Script_Execution_Order#My_Solution script.onload = callback; script.async = false; //将script元素的async设为false,能够保证script的执行顺序与请求顺序保持一致 script.src = targetUrl; } else{ script.onload = callback; script.src = targetUrl; } }
实际上,当你在页面建立一个img节点,并将其src指向一个脚本文件,在部分浏览器里一样可以起到文件预加载的做用,那么LABjs的做者是否是没有想到这一点呢?