LABjs使用与分析

目前业界商用的JS文件加载器有LABjs,Require.js,Sea.js。后两者同时又是模块加载器,很多网站/软件并不是按照AMD/CMD规范来开发的,只有LAB.js在大部分网站/软件上可以即插即用,下面分析一下LAB.js。

 

LAB.js即loading and blocking,并行的加载脚本文件,同时同步的等待执行。

实例:

$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('./module1.js')
    .script('./module2.js')

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

 

调试信息跟踪分析:

//这三个执行是并行加载完以后,执行的3个wait操作
驱动执行的函数advance_exec_cursor, chain length:2  exec_cursor:0 LAB.js:46
驱动执行的函数advance_exec_cursor, chain length:4  exec_cursor:0 LAB.js:46
驱动执行的函数advance_exec_cursor, chain length:6  exec_cursor:0 LAB.js:46
//因为request_script函数中setTimeout(f,0),所以加载会滞后于wait操作
start script load (ordered async): http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js LAB.js:46
start script load (ordered async): http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js LAB.js:46
start script load (ordered async): http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js LAB.js:46
start script load (ordered async): http://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.pack.js LAB.js:46
start script load (ordered async): file:///D:/Users/sj_yu/Desktop/work/20140408/LABjs/./module1.js LAB.js:46
start script load (ordered async): file:///D:/Users/sj_yu/Desktop/work/20140408/LABjs/./module2.js LAB.js:46
script execution finished: http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js LAB.js:46
script execution finished: http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js LAB.js:46
//按顺序执行完第一组执行链,也就是jquery和lodash,执行完JS后,调用advance_exec_cursor来探测执行游标是否需要移动
驱动执行的函数advance_exec_cursor, chain length:6  exec_cursor:0 LAB.js:46
//执行第二组执行链
$LAB.wait() executing: function (){
         // console.log(window.$)
         // console.log(window._)
    } LAB.js:46
//执行第三组执行链
script execution finished: http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js LAB.js:46
script execution finished: http://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.pack.js LAB.js:46
//执行完第三组后,触发advance_exec_cursor
驱动执行的函数advance_exec_cursor, chain length:6  exec_cursor:2 LAB.js:46
//第四组执行链
$LAB.wait() executing: function (){
         // console.log(plugin1Function)
         // console.log(plugin2Function)
    } LAB.js:46
//第五组执行链
script execution finished: file:///D:/Users/sj_yu/Desktop/work/20140408/LABjs/./module1.js LAB.js:46
script execution finished: file:///D:/Users/sj_yu/Desktop/work/20140408/LABjs/./module2.js LAB.js:46
驱动执行的函数advance_exec_cursor, chain length:6  exec_cursor:4 LAB.js:46
//执行第六组执行链
$LAB.wait() executing: function (){
        // console.log(module1Function)
        // console.log(module2Function)
    } 

 

 

LAB.js关键代码分析:

//核心代码
(function(global){

    function create_sandbox() {

        //加载脚本,用到的方式有document.createElement('script'),xhr
        function do_script() {
            //脚本加载
            if(需要预加载) {
                if(是否默认支持预加载) {
                    if(是否支持preload属性) {
                        script.preload = true;
                    } else {
                        script.onreadystatechage = function() {
                            if (script.readyState == "loaded") onload();
                        }
                    }
                    script.src = src;
                } else if(是否用XHR方式) {
                    new XMLHttpRequest();
                } else {
                    script.type = "text/cache-script";
                    create_script_load_listener();
                    script.src = src;
                }
            } else if(可以异步加载) {
                script.async = false; //强制同步执行
                create_script_load_listener();
                script.src = src;
            } else {
                create_script_load_listener();
                script.src = src;
            }
        }

        //创建执行链
        function create_chain() {

            var chain = [];//执行链

            //执行完JS调用该函数
            function chain_script_executed() {
                advance_exec_cursor();
            }

            //主动执行每个执行链
            function advance_exec_cursor() {
                while(执行游标 < chain.length) {
                    if(执行链是wait中的函数) {
                        执行wait函数
                    } else if(该执行链还没执行完) {

                    } 

                    游标++;
                }

                if (游标 == chain.length) {
                    执行停止
                }
            }

            //执行链api
            var chainedAPI = {
                script: function() {
                    do_script();

                    return chainedAPI;//支持链式调用
                },

                wait: function() {
                    if(arguments.length > 0) {
                        chain.push(arguments)
                    }

                    advance_exec_cursor();

                    return chainedAPI;//支持链式调用
                }
            }

            return {
                script:chainedAPI.script, 
                wait:chainedAPI.wait
            };
        } //end of create_chain

        //整个$LAB的接口
        var instanceAPI = {
            script:function(){
                return create_chain().script.apply(null,arguments);
            },
            wait:function(){
                return create_chain().wait.apply(null,arguments);
            }
        };

        return instanceAPI;
    } // end of create_sandbox

    //create_sandbox()返回 instanceAPI,包含script,wait等接口
    global.$LAB = create_sandbox();  
})(this);

 

 

总结:

优点:LABjs的接口设计非常轻,api很清晰,现有项目可以快速上手,大幅改进页面性能。相对于多个JS文件压缩到一个JS文件,又有不阻塞图片,css加载和模块化的优势。

缺点:目前没有靠谱的grunt插件,打包困难。

 

与Require.js和Sea.js的比较请参考:

http://www.zhihu.com/question/20342350

DailyJS对LABjs的解析:

http://dailyjs.com/2011/08/15/code-review/

 

 

 

 

posted @ 2014-04-08 21:34  aotoYu  阅读(426)  评论(0编辑  收藏  举报