Skip to content
返回

利用函数的惰性载入提高javascript代码性能

假装有个需求

我们现在需要写一个 foo 函数,这个函数返回首次调用时的 Date 对象,注意是首次

普通方法

var t;
function foo() {
    if (t) return t;
    t = new Date()
    return t;
}

问题有两个,一是污染了全局变量,二是每次调用 foo 的时候都需要进行一次判断。

首先解决污染全局变量的问题

  1. 闭包

var foo = (function() {
    var t;
    return function() {
        if (t) return t;
        t = new Date();
        return t;
    }
})();
  1. 函数对象

    //函数也是一种对象,利用这个特性,我们也可以解决这个问题。
    function foo() {
        if (foo.t) return foo.t;
        foo.t = new Date();
        return foo.t;
    }

不过依旧没有解决调用时都必须进行一次判断的问题。

解决的方案就是称之为惰性载入的技巧。

​ 所谓惰性载入,就是说函数的if分支只会执行一次,之后调用函数时,直接进入所支持的分支代码。 有两种实现惰性载入的方式,第一种事函数在第一次调用时,对函数本身进行二次处理,该函数会被覆盖为符合分支条件的函数,这样对原函数的调用就不用再经过执行的分支了, 我们可以用下面的方式使用惰性载入重写 foo().

var foo = function() {
    var t = new Date();
    foo = function() {
        return t;
    };
    return foo();
};

常见应用举例

在DOM 事件添加中,为了兼容现代浏览器和万恶的 IE 浏览器,我们需要对浏览器环境进行一次判断:

function addEvent (type, el, fn) {
    if (window.addEventListener) {
        el.addEventListener(type, fn, false);
    }
    else if(window.attachEvent){
        el.attachEvent('on' + type, fn);
    }
}

​ 每次调用 addEvent 函数的时候,它都要对浏览器所支持的能力进行检查,首先检查是否支持 addEventListener 方法,如果不支持,再检查是否支持 attachEvent 方法。 这个过程在 addEvent 函数每次调用的时候都要走一遍,其实,如果浏览器支持其中的一种方法,那么他就会一直支持了,就没有必要再进行其他分支的检测了, 也就是说,if 语句不必每次都执行,代码可以运行的更快一些。

function addEvent (type, el, fn) {
    if (window.addEventListener) {
        addEvent = function (type, el, fn) {
            el.addEventListener(type, fn, false);
        }
    }
    else if(window.attachEvent){
        addEvent = function (type, el, fn) {
            el.attachEvent('on' + type, fn);
        }
    }
}

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

​ 上面这种方法会在函数第一次调用时损失一点性能,有可能造成用户第一次使用功能时产生卡顿.使用闭包可以解决这个问题.

var addEvent = (function(){
    if (window.addEventListener) {
        return function (type, el, fn) {
            el.addEventListener(type, fn, false);
        }
    }
    else if(window.attachEvent){
        return function (type, el, fn) {
            el.attachEvent('on' + type, fn);
        }
    }
})();

​ 虽然利用闭包在第一次调用函数时就不会损失性能了,但是会在代码加载时会损失一点性能。所以只能具体情况具体分析了.


 

上一篇
没有人会和你说的HTTP中GET与POST的区别
下一篇
前端跨域的几种解决办法