LABjs里的动态加载脚本文件,是指页面的js脚本执行时,通过多种方法去加载外部的js(主要区别于html页面里,通过标签静态加载的脚本)
动态加载脚本的方式有很多,优缺点不一,此处不赘述,有兴趣的童鞋可以参见本文末尾的参考链接 :)。
LABjs里主要使用了三种技巧,分别为Script Element、XHR Injection以及Cache Trick
首先对这三种加载方式进行简单介绍,第四部分再分析LABjs源码实现里面对着三种方式分别的使用场景
Script Element(LABjs默认采用加载方式)
最常见的脚本动态加载方式,优点很多,包括:1、实现简单 2、可跨域 3、不会阻塞其他资源的加载 等
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){//当请求的脚本文件是否进行预加载:1、需要预加载 2、浏览器支持预加载if(supportRealPreloading){//如果支持真正的预加载if(supportPreloadPropNatively){//支持通过设置script标签的preload属性,实现script的预加载,以及分离加载和执行//Nicholas C. Zakas大神的美好愿望,尚未有浏览器支持:http://www.nczonline.net/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为预加载后的回调}
}elseif(inSameDomain){//非跨域,采用XHR Injection:请求的脚本与当前页面处于同一个域xhr=newXMLHttpRequest();//由于上个判断已经将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小组接受并放入草案:http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order#My_Solutionscript.onload =callback;
script.async=false;//将script元素的async设为false,可以保证script的执行顺序与请求顺序保持一致script.src =targetUrl;
}else{
script.onload=callback;
script.src=targetUrl;
}
}
实际上,当你在页面创建一个img节点,并将其src指向一个脚本文件,在部分浏览器里同样能够起到文件预加载的作用,那么LABjs的作者是不是没有想到这一点呢?
不少LABjs的使用者都向kyle提过上面这个问题,key表示:在现有加载策略已经能够满足需求的情况下,不想让LABjs的设计变得更复杂了(非原话)