一般性的,当我们需要加载js文件的时候都会使用script标签来实现,类似于如下代码:

代码如下:
<script type="text/javascript" src="example.js"></script>

但是直接使用script标签来加载js文件会有如下一些缺点:

1.严格的读取顺序。由于浏览器按照<script>在网页中出现的顺序,读取Javascript文件,然后立即运行,导致在多个文件互相依赖的情况下,依赖性最小的文件必须放在最前面,依赖性最大的文件必须放在最后面,否则代码会报错。

2.性能问题。浏览器采用"同步模式"加载<script>标签,也就是说,页面会"堵塞"(blocking),等待javascript文件加载完成,然后再运行后面的HTML代码。当存在多个<script>标签时,浏览器无法同时读取,必须读取完一个再去读取另一个,造成读取时间大大延长,页面响应缓慢。

这个时候我们就会想到去动态加载JS,动态加载js的实现方法类似于如下代码

代码如下:
/*
*@desc:动态添加script
*@param src:加载的js文件的地址
*@param callback:js文件加载完成之后需要调用的回调函数
*@demo:
addDynamicStyle('http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js', function () {
    alert('携程服务器上的lab.js加载完成')
});
*/
function addDynamicJS(src, callback) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.src = src[i];
    script.charset = 'gb2312';
    document.body.appendChild(script);
    if (callback != undefined) {
        script.onload = function () {
            callback();
        }
    }
}

这样不会造成页面堵塞,但会造成另外一个问题:这样加载的Javascript文件,不在原始的DOM结构之中,因此在DOM-ready(DOMContentLoaded)事件和window.onload事件中指定的回调函数对它无效。

这个时候我们就会想到用一些外部函数库来有效的管理JS加载问题。

下面进入正题说说LAB.js

LAB.js

如果我们使用传统的方法来加载js的话,写的代码一般会如下方代码所示风格。

代码如下:
<script src="aaa.js"></script>
    <script src="bbb-a.js"></script>
    <script src="bbb-b.js"></script>
    <script type="text/javascript">
        initAaa();
        initBbb();
    </script>
    <script src="ccc.js"></script>
    <script type="text/javascript">
        initCcc();
    </script>

如果我们使用LAB.js的话,要实现上述代码功能,则使用如下方式

代码如下:
<!--先加载lab.js库-->
    <script src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js"></script>
    <script type="text/javascript">
        $LAB
        .script("aaa.js").wait()//不带参数的.wait()方法表示立即运行刚才加载的Javascript文件
        .script("bbb-a.js")
        .script("bbb-b.js")//依次加载aaa.js bbb-a.js bbb-b.js  然后执行initAaa initBbb
        .wait(function () {//带参数的.wait()方法也是立即运行刚才加载的Javascript文件,但是还运行参数中指定的函数。
            initAaa();
            initBbb();
        })
        .script("ccc.js")//再加载ccc.js 加载完成ccc.js之后执行initCcc方法
        .wait(function () {
            initCcc();
        });
    </script>

可以同时运行多条$LAB链,但是它们之间是完全独立的,不存在次序关系。如果你要确保一个Javascript文件在另一个文件之后运行,你只能把它们写在同一个链操作之中。只有当某些脚本是完全无关的时候,你才应该考虑把它们分成不同的$LAB链,表示它们之间不存在相关关系。

一般性的使用示例

代码如下:
$LAB
.script("script1.js") // script1, script2, and script3 相互不依赖, 可以按照任意的顺序执行
.script("script2.js")
.script("script3.js")
.wait(function(){
    alert("Scripts 1-3 are loaded!");
})
.script("script4.js") //必须等待script1.js,script2.js,script3.js执行完毕之后才能执行
.wait(function(){script4Func();});
代码如下:
$LAB
.script("script.js")   
.script({ src: "script1.js", type: "text/javascript" })
.script(["script1.js", "script2.js", "script3.js"])
.script(function(){
    // assuming `_is_IE` defined by host page as true in IE and false in other browsers
    if (_is_IE) {
        return "ie.js"; // only if in IE, this script will be loaded
    }
    else {
        return null; // if not in IE, this script call will effectively be ignored
    }
})

在控制台看LAB.js的加载信息

如果你想调试或者说在控制台看各个js加载信息的话,可以使用$LAB.setGlobalDefaults 方法,具体使用请看代码示例。

代码如下:
<!--先加载携程的LAB库  lab.js在网上也可以下载-->
    <script type="text/javascript"
src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js"
charset="gb2312"></script>

<script type="text/javascript">

$LAB.setGlobalDefaults({ Debug: true }) //打开调试

$LAB
            //第一个执行链
           .script('http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js')

//第二个执行链
           .wait(function () {
               //console.log(window.$)
               //console.log(window._)
           })

//第三个执行链
           .script('http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.pack.js')

//第四个执行链
           .wait(function () {
               // console.log(plugin1Function)
               // console.log(plugin2Function)
           })

//第五个执行链
           .script('js/aaa.js')
           .script('js/bbb.js')

//第六个执行链
           .wait(function () {
               // console.log(module1Function)
               // console.log(module2Function)
           })
    </script>

这个时候打开控制台,看信息,如下图所示:

实例

  //加载大的背景图,不能等背景图先显示出来再执行html代码

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/js/sign.min.js")

  .wait() //立即执行

  </script>

  </body>

  //除了背景图还有轮换图,目前只用到这两种

  <html>

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/xxx/js/jquery.flexslider.min.js")

  .wait(function(){

  //banner 滚动

  $('#js_banner').flexslider({
                namespace:"",
                animation: "fade",
                selector: ".slides > li",
                pauseOnAction:false,
                controlNav:true,
                slideshowSpeed: 5000
            });    
    
            $('#whatsnew_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed:50,
                minItems: 4,
                maxItems: 5
            });
            $('#seller_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            $('#specials_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            
            $("#seller_pros").hide();
            $("#specials_pros").hide();
            $("#whatsnew_pros").show();

  })

  </script>

  </body>
  </html>

JavaScript文件加载器LABjs API详解

  在《高性能JavaScript》一书中提到了LABjs这个用来加载JavaScript文件的类库,LABjs是Loading And Blocking JavaScript的缩写,顾名思义,加载和阻塞JavaScript,而它的API script()和wait()则优雅地实现了这两个功能,我在高性能JavaScript 加载和执行一文中也简单讲解了这两个核心API的用法。当然,LABjs还有更多的API,本文用实例讲解下LABjs其他API。

$LAB.setGlobalDefaults() & $LAB.setOptions()

  两者所能设置的参数完全一致,不同的是,前者是全局设置,作用在所有的$LAB链上;后者出现在某条链的开头位置(后面接script()、wait()等),该设置只作用在这条链上。该参数可以是一个包含多个键值对的对象

  • AlwaysPreserveOrder

  一个布尔值(默认false),如果设置为true,则每个script()后都会默认设置一个wait(),使得链上的脚本一个个执行。

$LAB
.setOptions({AlwaysPreserveOrder:true}) // tells this chain to implicitly "wait" on
// execution (not loading) between each script
.script("script1.js") // script1, script2, script3, and script4 *DO* depend on each
.script("script2.js") // other, and will execute serially in order after all 4 have have
.script("script3.js") // loaded in parallel
.script("script4.js")
.wait(function(){script4Func();});
  • UseLocalXHR

  一个布尔值(默认true),如果是true的话,LABjs会用XHR Ajax去预加载同域的脚本文件。值得注意的是,只应用在老式的Webkit浏览器(那些既不能使用ordered-async也不能实现真正的预加载的浏览器),而且同域的情况下,该设置才起效(不然直接无视)

  • CacheBust & AllowDuplicates

  LABjs对于缓存有一些奇怪的处理(关于缓存,可以参考我前面的一篇文章浏览器缓存机制浅析),比如如下代码:

$LAB.script('index.js');

  很简单对吧?第一次载入,没有任何问题,HTTP200从server端下载。但是f5后:

  (2015-8-3 这个问题有点诡异,有时HTTP304,有时HTTP200from cache 我也在github上询问了作者 LABjs reads from cache when f5,回复的大概意思是cache和labjs没有任何关系,只和服务器和浏览器设置有关)

  居然是从缓存读取的!这就是说服务端的改动,对它不起效果!而通常情况下f5后是会向服务器发送请求的,如果服务端文件没有修改返回HTTP304读取缓存,如果修改了文件直接load新的。针对这个问题我们可以使用CacheBust选项:

$LAB.setGlobalDefaults({CacheBust: true})
$LAB.script('index.js');

  这样就能保证每次都从服务端读取文件(从不读取缓存)。

  还有一个问题,对于几个相同的请求,LABjs默认只会执行一次:

$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  实际上index.js这个文件只执行了一次!如果index.js里的代码是打印hello world,也就是说只会被打印一次。如何做到能打印三次?用AllowDuplicates:

$LAB.setGlobalDefaults({AllowDuplicates: true})
$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  实际上上面的代码,尽管会执行三次index.js,但是请求只有一次,其他两个都是缓存读取,而且如前面所说,如果服务端修改了,也会从缓存读取,这太可怕了。所以AllowDuplicates可以配合CacheBust使用

$LAB.setGlobalDefaults({AllowDuplicates: true, CacheBust: true})
$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  其实就是带了一串代表请求唯一的字符串,这在ajax请求中很常见。

  • BasePath

  一个字符串(默认空串),会将这个字符串加在每个script()里的URL的最前面。

  • Debug

  一个布尔值(默认false),如果开启debug选项的话,会在控制台打印信息,需要注意的是,只有使用了LAB-debug.min.js或者LAB.src.js该选项才work。

$LAB.script() & $LAB.wait()

  script()里的参数可以是很多形式,比如字符串(文件的相对路径或者绝对路径)、对象(src、type、charset src必须)、数组或者方法(或者前者们的组合),更多demo可以参考Example 8 below。前三者很好理解,这里简单提下参数为function的情况,当script()里的参数是个匿名的function的时候,该function会立即执行,它可以return一个值,而该值必须是以上说的string、object或者array形式,相当于给该script()赋值了。

$LAB
.script(function(){
// assuming `_is_IE` defined by host page as true in IE and false in other browsers
if (_is_IE) {
return "ie.js"; // only if in IE, this script will be loaded
}
else {
return null; // if not in IE, this script call will effectively be ignored
}
})
.script("script1.js")
.wait();

$LAB.queueScript() & $LAB.queueWait() & $LAB.runQueue() & $LAB.sandbox()

  script()和wait()会使得脚本立即执行(除非设置定时器),但是queueScript()和queueWait()能使得脚本在任意时刻执行,执行的时候带上runQueue()就行了。

var a = $LAB.queueScript('index.js').queueWait(function() {
console.log('hello world');
}); setTimeout(function() {
a.runQueue()
}, 1000);

  如上脚本就能在1000ms后执行,这样的效果貌似script()配合定时器也能实现,但是在未来某一不确定时刻执行就不行了(比如说一段指定代码后)。如果有两个链要在未来某时刻执行呢?

var a = $LAB.queueScript('index.js').queueWait(function() {
console.log('hello world');
}); setTimeout(function() {
a.runQueue()
}, 1000); var b = $LAB.queueScript('index2.js').queueWait(function() {
console.log('hello world');
}); setTimeout(function() {
b.runQueue()
}, 2000);

  如上代码并没能得到预想的结果(实际上1000ms后一起输出),这时就需要用sandbox()创建一个新的实例。

var a = $LAB.queueScript('index.js').queueWait(function() {
console.log('hello world');
}); setTimeout(function() {
a.runQueue()
}, 1000); var b = $LAB.sandbox().queueScript('index2.js').queueWait(function() {
console.log('hello world');
}); setTimeout(function() {
b.runQueue()
}, 2000);

$LAB.noConflict()

  使用noConflict()会将当前版本的LABjs回滚到旧的版本。(2015-08-04 这个解释应该是错的)

  read more from LAB documentation

github LAB.js 2.0.3及以下版本版本https://github.com/getify/LABjs

       3.0目前正在进行重写中https://github.com/getify/LABjs/tree/v3.0

参考自:https://www.jb51.net/article/61488.htm

    https://www.cnblogs.com/zichi/p/4689008.html

动态加载JS函数的更多相关文章

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

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

  2. jquery getScript动态加载JS方法改进详解[转载]

    转载自http://www.jb51.net/article/31973.htm 有许多朋友需要使用getScript方法动态加载JS,本文将详细介绍此功能的实现方法     $.getScript( ...

  3. 动态加载js css 插件

    简介 动态加载js,css在现在以及将来肯定是很重要的.目前来看前端代码编写的业务量已经远远超过后端编写的.随着对用户体验度逐渐增强,前端业务复杂,加载速度变得很慢很慢.为了解决这个问题,目前出现的两 ...

  4. js动态加载js css文件,可以配置文件后辍,防止浏览器缓存

    js的引用,在浏览器,或微信上访问经常会遇到文件改了,但就是没有更新的问题,使用此函数可以轻松解决缓存问题只需要把js的引用方式改为使用此函数加载即可 源码如下: /** * js动态加载js css ...

  5. JavaScript 之 动态加载JS代码或JS文件

    2.动态加载JS文件 <script type="text/javascript"> function loadScript(url, callback) { var ...

  6. jquery动态加载js/css文件方法

    先来看jquery自带的getSrcript文件 方法 代码如下 复制代码 $.getScript(url,callback) 实例 代码如下 复制代码 var testVar = 'New JS l ...

  7. 动态加载js和css的jquery plugin

    一个简单的动态加载js和css的jquery代码,用于在生成页面时通过js函数加载一些共通的js和css文件. //how to use the function below: //$.include ...

  8. JavaScript 元素的插入顺序以及动态加载js

    *****************记录下今天的心得***************** 1.元素的插入顺序 需求:异步从后台读取两个数据a和b,并动态加载到父容器x中,要求a必须在b的左边 实际情况:一 ...

  9. jquery getScript动态加载JS方法改进详解

    有许多朋友需要使用getScript方法动态加载JS,本文将详细介绍此功能的实现方法 $.getScript(url,callback) 这个方法是jquery自身提供的一个用于动态加载js的方法.当 ...

随机推荐

  1. SQL SERVER的锁机制(一)——概述(锁的种类与范围)

    锁定:通俗的讲就是加锁.锁定是 Microsoft SQL Server 数据库引擎用来同步多个用户同时对同一个数据块的访问的一种机制. 定义:当有事务操作时,数据库引擎会要求不同类型的锁定,如相关数 ...

  2. C#通过字符串名称来调用对应字符串名称的方法

    前段时间在一个项目中,在一个地方要将函数所在类中的方法都调用一遍,但是否调用要通过配置文件中的内容决定.所以为了减少代码量,在网上查了相关信息,终于成功的将其应用到了项目中,我在这里将我做的一个简单例 ...

  3. 在.net中修改Webbrowser控件的IE版本

    根据32位.64位系统来分别修改对应的注册表路径的键值对,不需要重启程序. /// <summary> /// 修改Webbrowser控件模拟的IE版本 /// </summary ...

  4. atom编辑器社区插件推荐

    atom是github出品的文本编辑器,为开发者又提供了一款易用.牛逼的文本编译器.在开始接触前端并从工作开始一直用webstrom来进行前端开发,开始使用时,被他各种强大神奇的功能给折服:支持zen ...

  5. mac下查看jdk安装版本及安装目录

    使用IntelliJ idea新建工程时需要查看jdk安装目录,记录下来为以后备用. mac自带jdk,查看jdk版本: IcarusdeMacBook-Pro:~ icarus$ java -ver ...

  6. 最小割(zjoi2011,bzoj2229)(最小割树)

    小白在图论课上学到了一个新的概念--最小割,下课后小白在笔记本上写下了如下这段话: "对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点\(s,t\)不在同一个部分中,则称 ...

  7. WebDriver高级应用实例(2)

    2.1在日期选择器上进行日期选择 被测网页的网址: https://www.html5tricks.com/demo/Kalendae/index.html Java语言版本的API实例代码 impo ...

  8. node-rsa非对称加密

    写在最前:此文的目的是介绍编码,减少刚接触时的弯路,所以内容且不做详细累述 一.使用 node-rsa 进行非对称加解密 因为 比特币 中使用的非对称加密,所以在npm中对比找到一个比较方便也直观的库 ...

  9. 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)

    Please note that when you are working on the programming exercise you will find comments that say &q ...

  10. Spring Boot打包war jar 部署tomcat

    概述 1.Spring Boot聚合工程打包war部署Tomcat 2.Spring Boot打包Jar,通过Java -jar直接运行. 3.提供完整pom.xml测试项目 至github 4.项目 ...