代码改变世界

JavaScript惰性载入函数

2013-03-03 23:14  youxin  阅读(281)  评论(0编辑  收藏  举报

因为浏览器之间行为的差异,多数JavaScript代码包含了大量的if语句,将执行引导到正确的代码中。看看XMLHttpRequest(XHR)对象中的createXHR()函数:

function createXHR(){
    if(typeofXMLHttpRequest!="undefined"){
        returnnewXMLHttpRequest();
    }elseif(typeofActiveXObject!="undefined"){
        if(typeof arguments.callee.activeXString !="string"){
            var versions =["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
            for(var i =0, len = versions.length; i < len; i++){
                try{
                    newActiveXObect(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    break;
                }catch(ex){
                    //跳过
                }
            }
        }
        returnnewActiveXObect(arguments.callee.activeXString);
    }else{
        thrownewError("No XHR object available.");
    }}

每次调用createXHR()的时候,它都要对浏览器所支持的能力仔细检查。首先检查内置的XHR,然后测试有没有基于ActiveX的XHR,最后如果没有发现的话就抛出一个错误。每次调用该函数都是这样,即使每次调用时分支的结果都不变:如果浏览器支持内置XHR,那么它就一直支持了,那么这种测试就变得没有必要了。即使只有一个if语句的代码,也肯定要比没有if语句的慢,所以如果if语句不必每次执行,那么代码可以运行的更快一些。解决方案就是称之为惰性载入的技巧。

惰性载入表示函数执行的分支仅会发生一次:即函数第一次调用的时候。在第一次调用的过程中,该函数会覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。例如,可以用下面的方式使用惰性载入重写createXHR():

function createXHR(){
    if(typeofXMLHttpRequest!="undefined"){
        createXHR =function(){
            returnnewXMLHttpRequest();
        }
    }elseif(typeofActiveXObject!="undefined"){
        createXHR =function(){
            if(typeof arguments.callee.activeXString !="string"){
                var versions =["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"];
                for(var i =0, len = versions.length; i < len; i++){
                    try{
                        var xhr =newActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        return xhr;
                    }catch(ex){
                        //跳过
                    }
                }
            }
            returnnewActiveXObect(arguments.callee.activeXString);
        }
    }else{
        createXHR =function(){
            thrownewError("No XHR object available.");
        };
    }
    return createXHR();}

在这个惰性载入的createXHR()中,if语句的每一个分支都会为createXHR变量赋值,有效覆盖了原有的函数。最后一步便是调用新赋值的函数。下一次调用createXHR()的时候,就会直接调用分配的函数,这样就不用再次调用if语句了。

惰性载入函数有两个主要有点。第一,要执行的适当代码只有当实际调用函数时才进行。某些JavaScript库一开始就根据浏览器功能或者怪癖执行很多代码分支,将所有东西实先设置好。惰性载入则将这些计算尽可能的推迟,保证了恰当的功能而又不影响初始脚本的执行时间。第二,尽管第一次调用该函数会因为额外的第二个函数调用而稍微慢一点,但是所有后续的调用都会更快,因为后面避免了多重if条件。