11

在 Firefox 中,以下两个函数之间似乎存在很大的性能差异:

var n1 = 12;

var add1 = function(n2){
    return n1 + n2;
}

var add2 = (function(){
    return function(n2){
            return n1 + n2;
    }
})();

我认为这一定是由于引入了另一个级别的范围,因此创建了第三个示例,其中变量缓存了一个级别。但这显示了更大的减少(80%!)

var add3 = (function(){
    var cn1 = n1;
    return function(n2){
            return cn1 + n2;
    }
})();

我原以为这里的关闭会缩小性能差距,而不是扩大它。有人知道这里发生了什么吗?

jsPerf 测试页面:http: //jsperf.com/variable-scope-speed

4

2 回答 2

2

这很有趣,但我在这里的小测试似乎证实了我之前的假设,即jsPerf环境会影响作用域和作用域链查找本身。我没有深入研究“如何”和“为什么”,但这是我的小测试脚本:

var n1 = 12;

var add1 = function(n2){
        return n1 + n2;
}

var add2 = (function(){
        return function(n2){
                return n1 + n2;
        }
})();

var add3 = (function(){
        var cn1 = n1;
        return function(n2){
                return cn1 + n2;
        }
})();

var add4 = function( n2, n1 ) {
    return n2 + n1;
}.bind(null, n1);


var tests = [add1, add2, add3, add4],
    start, stop, loops;

tests.forEach(function( fnc ) {
    loops = 100000;

    start = Date.now();
    while( loops-- ) {
        fnc( 2 );
    }
    stop = Date.now();

    console.info('Method ', fnc.name || fnc.toString(), ': ', stop - start, ' ms.');
});

我的 FireFox 14 上的结果如下所示:

方法add1:570ms。
方法add2:566ms。
方法add3:414ms。
方法add4:479ms。

最新的 Chrome 结果:

方法add1:199ms。
方法add2:136ms。
方法add3:85ms。
方法add4:144ms。

这肯定看起来更合理。封闭的作用域链查找必须总是更快,这仅仅是因为存在较短的查找链。即使所有现代浏览器通常不进行经典的范围链查找,我也知道这一点。无论如何,由于浏览器为自由(或超出范围)变量创建了非常聪明的查找表,所有结果至少应该是相同的。过度优化全局对象访问 IMO 没有任何意义。

正如您所注意到的,我为绑定方法创建了一个额外的测试用例。

于 2012-08-24T14:40:30.343 回答
0
var n1 = 12;

// "add1" is superfast in Firefox, but not in Chrome. Why?
// it seems Firefox is smarter in retrieving n1 value from global scope
var add1 = function(n2){
        return n1 + n2;
}

// "add2" is much slower in Firefox, but in Chrome the speed is almost equal to "add2"
// it seems that Firefox's smart retrieving from global scope is not applied in this case
// it is understandable that "add2" is slower, because the interpreter needs to go back two levels in the scope chain to find the "n1" variable value
var add2 = (function(){
        return function(n2){
                return n1 + n2;
        }
})();

// If JavaScript works as PHP, then it won't copy "n1" value in "cn1".
// If this is the case, then it is understandle why it is slower.
// The interpreter first needs to search and find "cn1" value;
// when it finally finds it in the previous scope level,
// then it needs to start a second "search and find travel", looking for the value.
// This means "cn1" does not contain "12", but a reference to it in the memory.
// While I don't know if this is how JavaScript engine works,
// I know that PHP does not create a copy of the value -
// both variables share the same content in the memory.
// Short story being: it is slower because it must perform two "searches" instead of one.
var add3 = (function(){
        var cn1 = n1;
        return function(n2){
                return cn1 + n2;
        }
})();
于 2012-08-24T14:36:59.637 回答