为了提高页面的打开和加载速度,我们经常把JS文件放在页面的尾部,但是有些JS必须放在页面前面,这样就会增加页面的加载时间;于是出现了按需动态加载的概念,这个概念就是当页面需要用到这个JS文件或者CSS渲染文件的时候,在去请求这些文件,这样就节省了页面的加载时间

LABjs 是一个很小的 JavaScript 工具,用来根据需要加载 JavaScript 文件,通过使用该工具可以提升页面的性能,避免加载不需用到的 JavaScript 文件,可以实现动态并行加载脚本文件,以及管理加载脚本文件的执行顺序。

简单示例

$LAB
.script("script1.js", "script2.js", "script3.js")
.block(function(){
// wait for all to load, then do something
script1Func();
script2Func();
script3Func();
});

介绍下LABJS的几个实例:

实例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大神的美好愿望,尚未有浏览器支持:/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的作者是不是没有想到这一点呢?

详谈LABJS按需动态加载js文件的更多相关文章

  1. 如何按需动态加载js文件

    JavaScript无非就是script标签引入页面,但当项目越来越大的时候,单页面引入N个js显然不行,合并为单个文件减少了请求数,但请求的文件体积却很大.这时候最好的做法就是按需引入,动态引入组件 ...

  2. 按需动态加载js

    有些时间我们希望能按需动态加载js文件,而不是直接在HTML中写script标签. 以下为示例代码: var js = document.createElement('script'); js.asy ...

  3. 动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数

    动态加载JS文件,并根据JS文件的加载状态来执行自己的回调函数, 在很多场景下,我们需要在动态加载JS文件的时候,根据加载的状态来进行后续的操作,需要在JS加载成功后,执行另一方法,这个方法是依托在加 ...

  4. ExtJS4.x动态加载js文件

    动态加载js文件是ext4.x的一个新特性,可以有效的减少浏览器的压力,提高渲染速度.如动态加载自定义组件 1.在js/extjs/ux目录下,建立自定义组件的js文件. 2.编写MyWindow.j ...

  5. Ext JS学习第十天 Ext基础之动态加载JS文件(补充)

    此文用来记录学习笔记: •Ext4.x版本提供的一大亮点就是Ext.Loader这个类的动态加载机制!只要遵循路径规范,即可动态加载js文件,方便把自己扩展组件动态加载进来,并且减轻浏览器的压力. • ...

  6. javascript动态加载js文件主流浏览器兼容版

    一.代码示例: <html> <head> <meta http-equiv="Content-Type" content="text/ht ...

  7. JavaScript动态加载js文件

    /********************************************************************* * JavaScript动态加载js文件 * 说明: * ...

  8. 动态加载js文件是异步的

    动态加载js文件是异步的. 今天调试一个错误,一个js方法各种调不到. 原因是因为所调方法的js文件是动态加载进来的. <script type="text/javascript&qu ...

  9. 动态加载js文件

    由于最近在弄echarts,关于地图类的效果,但是全国地图整体的js文件太大了,加载很耗费资源,所以要根据不同省份加载不同地区的js地图, 于是就想的比较简单, var script = docume ...

随机推荐

  1. MathType出现乱码公式怎么恢复

    在我们平时使用word上的数学公式编辑器的时候,有时一些公式会出现乱码的问题.这个时候可以改为使用MathType时,那么MathType出现乱码公式怎么恢复呢?如果只是少量公式可以手动重新输入,如果 ...

  2. IIS 使用多个https和通配证书解决方案

    环境:OS :WINDOWS 2008 IIS: IIS7 域名:三个二级域名 问题:由于一个网站只支持一个443,但可以通过更改配置得到绑定不同域名.但由于公用证书,所以问题出来.只能为一个二级域名 ...

  3. 如何通过phoenix中查看表的主键信息

    需求描述: 今天一个开发的同事让帮忙查看下表的主键列,在此记录下. 操作过程: 1.通过!primarykeys命令查看表的主键 !primarykeys SYNC_BUSINESS_INFO_BYD ...

  4. [spring] org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljav 解决

    严重: Exception sending context initialized event to listener instance of class org.springframework.we ...

  5. 工作流JBPM_day01:2-HelloWorld

    工作流JBPM_day01:2-HelloWorld 新建一个java工程Jbpm4.4 拷贝helloworld.jpdl.xml和helloworld.png文件出来压缩成helloworld.z ...

  6. php 如何得到不含前导0的时分秒

    通常我们获取时分秒是用 date("H:i:s") ,得到的效果是这样的 而如果想获取不含前导0的时分秒的话,就需要把前导0去掉. 如何去掉呢?我们来分析一下,07变7,20还是2 ...

  7. INSTALL_FAILED_INVALID_APK

    在项目中无意中把APP只写成了 xxx  没有xxx.xxx.xxx  掉坑里了,找了好久,给大家提不醒

  8. surfaceView和View的区别

    概念:view在UI线程去更新自己:而SurfaceView则在一个子线程中去更新自己 surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面 在UI的 ...

  9. 解决Xcode "The selected destination does not support the architecture " 错误错误

    XCODE编译运行项目后,发现工程编译后无法运行,出现:"The selected destination does not support the architecture for whi ...

  10. 详谈redis优化配置和redis.conf

    1. Redis.conf 配置参数: #是否作为守护进程运行 daemonize yes #如以后台进程运行,则需指定一个pid,默认为/var/run/redis.pid pidfile redi ...