javascript加载顺序LABjs

最基本的动态加载js程序如下:

function loadScript(url){
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.src = url;
  document.body.appendChild(script);
}

也可以添加回调函数:

function loadScript(url, callback){
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.src = url;
  script.defer = true;
  document.body.appendChild(script);

  callback = callback || function () {};
  script.onload = script.onreadystatechange = function () {
    if (!this.readyState || 'loaded' === this.readyState || 'complete' === this.readyState) {
      callback();
      this.onload = this.onreadystatechange = null;
      this.parentNode.removeChild(this);
    }
  }
  document.getElementsByTagName('head')[0].appendChild(script);
}

 

 
《高性能JavaScript》介绍过lab.js, 现在来看下使用方法

实例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主要采用加载方式

加载外部 js 的方法大致有这么几种:

方法 说明

XHR Eval       通过 Ajax 方式获取代码,并通过 eval 方式执行代码。
XHR Injection       通过 Ajax 方式获取代码,并在页面上创建一个 script 元素,将 Ajax 取得的代码注入。
Script in Iframe        通过 iframe 加载 js。
Script DOM Element        使用 JavaScript 动态创建 script DOM 元素并设置其 src 属性。
Script Defer/Async 严格来说,这一条不算是动态加载外部脚本的方法,但很多动态加载外部脚本的方法里都会用到 sctipt 的 defer 或 async 属性,所以也把它单独列在这儿。这个方法利用 script 的 defer 属性,让脚本“推迟”执行,不阻塞页面加载,或者设置 async 属性,让脚本异步执行。遗憾的是这两个属性不是所有浏览器都支持。
document.write Script Tag 通过 document.write 把 HTML 标签 script 写入到页面中。
cache trick 先使用自定义的 script 的 type 属性(如 <script type="text/cache" ...),甚至使用 Image、Object 等 HTML 对象将 js “预下载”(下载到浏览器缓存里),等真正需要执行对应代码时再将它真正地插入页面中。
Web Worker 部分浏览器支持 web worker 功能,可以创建一个 worker 在后台工作,包括加载外部脚本。

 


LABjs里主要使用了三种技巧,分别为Script Element、XHR Injection以及Cache Trick

 


四、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的设计变得更复杂了(非原话)

 

 

修改时间 2018-10-18

真诚赞赏,手留余香
赞赏
随机推荐
在 CentOS 8 上使用 DNF 管理软件包
MySQL DATE_FORMAT() 函数 格式化时间
在PDO中使用事务
跨域资源共享 CORS 详解「转载」
Filezilla Server和防火墙设置的相关知识(主动连接和被动连接)
CentOS 常用文件操作
Javascript高级选择器querySelector和querySelectorAll
修改Windows系统同步时间的频率和服务器
Nginx 报错 nginx accept() failed (24: Too many open files)
2015-2016前端知识体系