11

firefox では、次の 2 つの関数のパフォーマンスに大きな違いがあるようです。

var n1 = 12;

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

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

これは、別のレベルのスコープの導入によるものに違いないと考えたので、変数を 1 レベル上にキャッシュした 3 番目の例を作成しました。しかし、これはさらに大きな削減 (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 を過度に最適化しても意味がありません。

お気づきのとおり、バインドされたメソッド用に 1 つの追加のテスト ケースを作成しました。

于 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 に答える