详谈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的作者是不是没有想到这一点呢?

标签:LABJS,按需动态加载js
0
投稿

猜你喜欢

  • Django的ListView超详细用法(含分页paginate)

    2021-02-13 00:53:41
  • Python 中@lazyprop 装饰器的用法

    2022-11-30 16:42:10
  • 浏览器针对单服务器连接数问题

    2008-05-12 22:27:00
  • [PHP]常用正则表达式收集

    2024-05-03 15:34:49
  • 教程:纯CSS作的小灯笼效果

    2008-08-26 17:22:00
  • Python 读取 .gz 文件全过程

    2021-11-02 16:01:04
  • DWCS3-CSS布局之一CSS规则大纲

    2008-06-11 18:48:00
  • 用Asp修改注册表

    2008-01-04 12:33:00
  • Python简单实现图片转字符画的实例项目

    2023-02-24 02:01:47
  • python 自动化将markdown文件转成html文件的方法

    2021-09-16 16:04:40
  • Python实现softmax反向传播的示例代码

    2021-02-24 10:54:02
  • 浅谈在JupyterNotebook下导入自己的模块的问题

    2023-03-16 11:28:36
  • MySQL主从复制的原理及配置方法(比较详细)

    2024-01-28 18:21:02
  • Google的YSlow——Page Speed(附插件下载)

    2009-09-27 12:40:00
  • 刷新页面的几种方法小结(JS,ASP.NET)

    2024-05-28 15:37:33
  • SQL Server如何才能访问Sybase中的表

    2009-01-08 13:33:00
  • Go 语言简单实现Vigenere加密算法

    2024-05-08 10:14:04
  • Python pygame绘制文字制作滚动文字过程解析

    2022-06-10 13:21:11
  • MySQL 随机函数获取数据速度和效率分析

    2024-01-13 00:43:01
  • php实现用于计算执行时间的类实例

    2024-06-07 15:28:42
  • asp之家 网络编程 m.aspxhome.com