详谈LABJS按需动态加载js文件
作者:hebedich 发布时间:2024-04-23 09:20:56
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的作者是不是没有想到这一点呢?


猜你喜欢
- virtualenv 是用来创建一个虚拟的python环境的第三方包,一个专属于项目的python环境。安装virtualenv(请确保py
- 1. 训练运行时候指定GPU运行时候加一行代码:CUDA_VISIBLE_DEVICES=1 python train.py2. 运行过程中
- 一、闭包闭包相当于函数中,嵌套另一个函数,并返回。代码如下:def func(name): # 定义外层函数 def inner
- 过去一段时间人们似乎又非常热衷于探讨网络文档的印刷格式,涌现了很多与之相关的技术与理论资料,其中相当重要的一个领域就是关于印刷中字号和行高的
- 这里的内容以Linux进程基础和Linux文本流为基础。subprocess包主要功能是执行外部的命令和程序。比如说,我需要使用wget下载
- 在SQL Server日常的函数、存储过程和SQL语句中,经常会用到不同数据类型的转换。在SQL Server有两种数据转换类型:一种是显性
- asp.net的dropdownlist控件为我们的web应用提供了许多用处,但有一点我总感觉不爽的就是在使用dropdownlist的事件
- python协程只能运行在事件循环中,但是一旦事件循环运行,又会阻塞当前任务。所以只能在当前进程中再开一个线程,这个线程的主要任务是运行事件
- 1、golang中获取请求接口中数据(GET)方式一: API参数 ctx.Param(name string)或者ctx.Params.B
- 对于一般的图像提取轮廓,介绍了一个很好的方法,但是对于有噪声的图像,并不能很好地捕获到目标物体。比如对于我的鼠标,提取的轮廓效果并不好,因为
- 在日常运维中,如果涉及到用户管理,就一定会用到给用户设置密码的工作,其实吧,平时脑子里觉得设置个密码没什么,但要真让你随手敲一个12位带特殊
- * 表的建立关系数据库的主要特点之一就是用表的方式组织数据。表是SQL语言存放数据、查找数据以及更新数据的基本数据结构。在SQL语言中,表有
- 我们不可能直接通过node命令来管理远程站点,这样无法保证网站的可持续运行。我们用Forever来解决这个问题,它可以将NodeJS应用以后
- 本文实例讲述了Python存取XML的常见方法。分享给大家供大家参考,具体如下:目前而言,Python 3.2存取XML有以下四种方法:1.
- python turtle自定义画布背景色turtle是python一个简单好用的绘图包,它可以通过设计坐标来实时控制绘图。安装很简单,一行
- Detecting When The User Has Clicked Cancel One of the things you may w
- 脚本需求:每天备份mysql数据库,保留7天的脚本。存放在/opt/dbbak目录中。脚本名称为database_xxxx-xx-xx.sq
- 一、前言在Python提供了强大的模块支持,主要体现为不仅在Python标准库中包含了大量的模块(称为标准模块),而且还有很多第三方模块,另
- 开发自定义Web框架接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务。根据请求资源路径的后缀名进行判断:如果请求资源
- 函数局部变量 全局变量 及其作用域#简单类型(int str等)变量的局部变量与全局变量及其作用域的关系name = "xxx&q