JSX で Array#forEach が5倍以上速くなった話
JSX の進化速度が半端ない - ぐるぐる~ で紹介していただいているとおり、最新の JSX では function expression の型宣言を省略できるようになっています。これを利用して、たとえば配列の合計を求める場合、
var sum = 0; [ 1, 2, 3, 4, 5, 6, 7, 8 ].forEach(function (n) { sum += n; });
のように、JavaScript と 100% 同様に書くことができるようになりました。省略形を利用して [ ... ].forEach((n) -> { sum + n; }); でもいいです。
ところでこのコード、見た目は同じなんですが、実は JSX だと JavaScript よりも5倍以上速く動くんです。まだ最適化があまいところがあるのに。
なぜか。JavaScript の Array#forEach は配列の要素ごとに関数の呼び出しが発生するので遅いのです。じゃあ、
var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; var sum = 0; for (var i = 0; i < a.length; ++i) { sum += a[i]; }
と書けばいいのでしょうか。いえいえ、それではまだ不足です。ループの度に Array#length へのアクセスしているのが、足をひっぱります。JavaScript におけるプロパティアクセスは遅いのです。
var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; var sum = 0; for (var i = 0, aLen = a.length; i < aLen; ++i) { sum += a[i]; }
これなら、まあ合格です。ただ Safari だと for ループの中に var 宣言を入れると遅くなるので、さらに言うなら
var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; var sum = 0; var i, aLen; for (i = 0, aLen = a.length; i < aLen; ++i) { sum += a[i]; }
と書くべきなんですが…こんなバッドノウハウ、いちいち覚えたくないし使いたくないですね。
JSX なら、このような最適化を自動的にやってくれるわけです。楽チン楽チン。
以上、宣伝でした。ベンチマークは sum-of-array · jsPerf にあるのでお試しあれ。