LABJS源码浅析
一、关于LABjs的简单介绍
作者:Kyle Simpson
作用:动态并行加载脚本文件 以及 管理加载脚本文件的执行顺序
二、关于LABjs的使用
以下实例原文链接:http://www.au92.com/archives/labjs.html
更全更详细说明:http://labjs.com/documentation.php
实例1:
$LAB.script("script1.js")
.script("script2.js")
.script("script3.js")
.wait(function(){// 等待所有script加载完再执行这个代码块
script1Func();
script2Func();
script3Func();
});
实例2:
$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:
$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默认采用加载方式)
最常见的脚本动态加载方式,优点很多,包括: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为预加载后的回调
} }
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小组接受并放入草案:http://wiki.whatwg.org/wiki/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的作者是不是没有想到这一点呢?
不少LABjs的使用者都向kyle提过上面这个问题,key表示:在现有加载策略已经能够满足需求的情况下,不想让LABjs的设计变得更复杂了(非原话)
写在后面
此处仅仅简单对LABjs的作用、用法以及内部实现简单介绍了下,关于内部具体源代码实现的分析,留待下一篇文章
如有错漏,请指出 ,如有问题,欢迎回复以及邮件进一步交流 :)
参考资料:
oldj:《LABjs分析》
steve souders:《Loading Scripts Without Blocking》
Franky:《又说 动态加载 script. ie 下 script Element 的 readyState状态》
大魔I‘m png:《js并行加载,顺序执行》
后续阅读推荐:
Nicholas C. Zakas大神关于脚本加载的设想:http://www.nczonline.net/blog/2011/02/14/separating-javascript-download-and-execution/
kyle Simpson关于脚本加载的提案:http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order#My_Solution
kely Simpson关于Firefox某版本去掉脚本执行顺序保证的回应:http://blog.getify.com/ff4-script-loaders-and-order-preservation/
LABJS源码浅析的更多相关文章
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 【深入浅出jQuery】源码浅析2--奇技淫巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- Struts2源码浅析-ConfigurationProvider
ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface Configurat ...
- (转)【深入浅出jQuery】源码浅析2--奇技淫巧
[深入浅出jQuery]源码浅析2--奇技淫巧 http://www.cnblogs.com/coco1s/p/5303041.html
- HashSet其实就那么一回事儿之源码浅析
上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap, 本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...
- Android 手势识别类 ( 三 ) GestureDetector 源码浅析
前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势.所 以,用户绘制出的一个完整的手势是需要一定的代码 ...
- Android开发之Theme、Style探索及源码浅析
1 背景 前段时间群里有伙伴问到了关于Android开发中Theme与Style的问题,当然,这类东西在网上随便一搜一大把模板,所以关于怎么用的问题我想这里也就不做太多的说明了,我们这里把重点放在理解 ...
- 【深入浅出jQuery】源码浅析2--使用技巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- Android手势源码浅析-----手势绘制(GestureOverlayView)
Android手势源码浅析-----手势绘制(GestureOverlayView)
随机推荐
- SqlServer日期查询
一.sql server日期时间函数 Sql Server中的日期与时间函数 1. 当前系统日期.时间 select getdate() 2. dateadd 在向指定日期加上一段时间的基础上,返 ...
- 学了一个封装的jquery插件,感觉还成
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- commons-logging 和 log4j 之间的关系
我们在做项目时,日志的记录是必不可少的一项任务,而我们通常是使用 apache 的 log4j 日志管理工具.然而,在项目中,我们经常会看到两个 jar 包:commons-logging.jar 和 ...
- [C++程序设计]对“&”和“*”运算符
对“&”和“*”运算符再做些说明:(1) 如果已执行了“pointer_1=&a;”语句,请问&*pointer_1的含义是什么?“&”和“*”两个运算符的优先级别相同 ...
- oc语言--description方法和sel
一.description方法 Description方法包括类方法和对象方法.(NSObject类所包含) (一)基本知识 -description(对象方法) 使用NSLog和@%输出某个对象时, ...
- 分析java 嵌套类与内部类
一.什么是嵌套类及内部类? 可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类 ...
- TEA encryption with 128bit key
If anyone needs some basic encryption in software, here's one solution. This TEA implementation fits ...
- FileStream类
使用FileStream能够对对系统上的文件进行读.写.打开.关闭等操作.并对其他与文件相关的操作系统提供句柄操作,如管道,标准输入和标准输出.读写操作可以指定为同步或异步操作.FileStream对 ...
- hash_map和map的区别
hash_map和map的区别 分类: STL2008-10-15 21:24 5444人阅读 评论(0) 收藏 举报 class数据结构编译器存储平台tree 这里列几个常见问题,应该对你理解和使用 ...
- UESTC_最少花费 2015 UESTC Training for Dynamic Programming<Problem D>
D - 最少花费 Time Limit: 30000/10000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submi ...