Edited at

2017年度版 細かすぎて伝わらないJavaScriptの速度の話

More than 1 year has passed since last update.


概要

コードを書いていると誰もが気になってくる「どっちのほうがパフォーマンスに優れているの?」で、眠れない日々を過ごす人達のために、比較結果をまとめてみました。


実行環境

OS: macOS Sierra 10.12.5

Chrome: 58.0.3029.110 (64-bit)

Safari: 10.1.1


計測方法

10 回実行した結果の平均値です。


比較


シングルクオート VS ダブルクオート


コード

start = () => {

const retryCount = 1000000;
const startTime = new Date();
for (let i = 0; i < retryCount; i = i + 1) {
/* ダブルクオート
const text = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z" + i;
*/

/* シングルクオート
const text = 'abcde' + 'fghij' + 'klmno' + 'pqrst' + 'uvwxy' + 'z' + i;
*/

}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average
最速

シングルクオート
256.2 ms

ダブルクオート
241.5 ms


  • Safari

対象
Average
最速

シングルクオート
122.9 ms

ダブルクオート
122.3 ms


所感


ダブルクオートのほうが若干早いという結果になりましたが、ほぼ誤差の範囲なので

パフォーマンスを気にするよりも可読性を優先したほうが良さそうです。



if VS switch


コード

start = () => {

const startTime = new Date();
for (let i = 0; i < 10000000; i = i + 1) {
const x = 1;
/* if
if ( x === 1) {}
else if ( x === 2) {}
else if ( x === 3) {}
else {}
*/

/* switch
switch (x) {
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
*/

}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


条件に一致する場合 (x = 1)


  • Chrome

対象
Average
最速

if
155.5 ms

switch
157.8 ms


  • Safari

対象
Average
最速

if
204.2 ms

switch
210.4 ms


条件に一致しない場合 (x = 4)


  • Chrome

対象
Average
最速

if
182.9 ms

switch

182.7 ms


  • Safari

対象
Average
最速

if
207.7 ms

switch
213.2 ms


所感


if と switch の速度差は、ほぼ誤差の範囲だと思います。

if では else 処理で速度に差異があるため、else での処理を避けることに注力したほうが良さそうです。



インクリメント


コード

start = () => {

const startTime = new Date();
let x = 1;
for (let i = 0; i < 10000000; i = i + 1) {
/* x++; */
/* x = (x + 1); */
/* x = (x + 1)|0; */
}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average
最速

x++
145.6 ms

x=(x+1)
155.5 ms

x=(x+1)|0
162.1 ms


  • Safari

対象
Average
最速

x++
107.3 ms

x=(x+1)
110.3 ms

x=(x+1)|0
110.3 ms


所感


色々な記事で一番速いと言われていた x = (x + 1)|0 よりも x++ のほうが速かったという結果になりました。

どこかのタイミングでインクリメント処理が最適化されたのかもしれません。



文字連結


コード

start = () => {

const startTime = new Date();
const a = "abcde";
const f = "fghij";
const k = "klmno";
const p = "pqrst";
const u = "uvwxyz";
for (let i = 0; i < 1000000; i = i + 1) {
/* + 連結
let text = a + f + k + p + u + i;
*/

/* concat 連結
let text = a.concat(f).concat(k).concat(p).concat(u).concat(i);
*/

/* テンプレートリテラル
let text = `${a}${f}${k}${p}${u}${i}`;
*/

/* += 連結
let text = a;
text += f;
text += k;
text += p;
text += u;
text += i;
*/

}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average
最速

+ 連結
230.1 ms

concat 連結
329.2 ms

テンプレートリテラル
292.2 ms

+= 連結
230.2 ms


  • Safari

対象
Average
最速

+ 連結
177.2 ms

concat 連結
264.6 ms

テンプレートリテラル
144.4 ms

+= 連結
176.8 ms


所感


Safari と Chrome で差のある結果となりました。

concat 連結が最遅なので避けるとして、可読性を考えると変数を含む場合はテンプレートリテラルを使う方が良さそうです。



Undefined判定


コード

start = () => {

let x;
const startTime = new Date();
for (let i = 0; i < 10000000; i = i + 1) {
/* if (typeof x === 'undefined') {} */
/* if (x === undefined) {} */
/* if (x === void 0) {} */
/* if (!x) {} */
}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average
最速

typeof x === 'undefined'
150.4 ms

x === undefined
143.5 ms

x === void 0
143.1 ms

!x
158.1 ms


  • Safari

対象
Average
最速

typeof x === 'undefined'
106.2 ms

x === undefined
107 ms

x === void 0
106.8 ms

!x
104.7 ms


所感


Chrome では一番遅かった !x が Safariでは一番速いという結果になりました。

Safariのほうは速度は誤差の範囲だと思いますので、横着せずに !x 以外で判定したほうが良さそうです。



真偽判定


コード

start = () => {

const startTime = new Date();
const x = true;
for(let i = 0; i < 10000000; i = i + 1) {
/* if (x) {} */
/* if (x === true) {} */
/* if (!x) {} */
/* if (x === false) {} */
}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


真 判定


  • Chrome

対象
Average
最速

x
161.5 ms

x === true
189.6 ms


  • Safari

対象
Average
最速

x
111.5 ms

x === true
110 ms


偽 判定


  • Chrome

対象
Average
最速

!x
159.8 ms

x === false
185.8 ms


  • Safari

対象
Average
最速

!x
109.9 ms

x === false
107.8 ms


所感


Chrome と Safari で異なる結果となりました。

Safariのほうの差は誤差なので、個人的には省略型で書きたいです。



スコープ


コード

scope01 = 1;

class Test {
constructor() {
this.scope02 = 1;
}
start() {
let scope03 = 1;
const startTime = new Date();
for(let i = 0; i < 10000000; i = i + 1) {
/* scope01++; */
/* this.scope02++; */
/* scope03++; */
}
const endTime = new Date();
console.log(endTime - startTime);
}
}
start = () => {
const test = new Test();
test.start();
}


結果


  • Chrome

対象
Average
最速

scope01
247.3 ms

scope02
274.6 ms

scope03
156.9 ms


  • Safari

対象
Average
最速

scope01
116.3 ms

scope02
111.8 ms

scope03
110.1 ms


所感


Chrome の scope01 と scope02 の差があまり納得できませんが、基本的にはなるべく近いスコープを利用するほうが良いということで問題ないと思います。



New のコスト


コード

class Test {

constructor() {}
}
start = () => {
const startTime = new Date();
for(let i = 0; i < 10000000; i = i + 1) {
/* const test = 0; */
/* const test = new Test(); */
}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average

const test = 0
139.6 ms

const test = new Test()
399.2 ms

上 2 つの差
259.6 ms


  • Safari

対象
Average

const test = 0
223.9 ms

const test = new Test()
660.2 ms

上 2 つの差
436.3 ms


所感


何度も繰り返し new するケースも少ないと思うため、あまり気にしなくて良さそうです。



Try/Catchブロック のコスト


コード

start = () => {

const startTime = new Date();
for(let i = 0; i < 10000000; i = i + 1) {
/* なし
const x = 0;
*/

/* Try/Catch
try {
const x = 0;
   }
catch (exception) {}
*/

/* Try/Catch/Finally
try {
const x = 0;
   }
catch (exception) {}
finally {}
*/

}
const endTime = new Date();
console.log(endTime - startTime);
}


結果


  • Chrome

対象
Average

なし
144.5 ms

Try/Catch
20.3 ms

Try/Catch/Finally
22.1 ms


  • Safari

対象
Average

なし
227.5 ms

Try/Catch
224.3 ms

Try/Catch/Finally
225.1 ms


所感


Chrome の try/catchブロックを利用した場合が圧倒的に早すぎて意味がわかりませんでした。

どちらの場合も try/catchで囲む方が早くなっています。

スコープの問題でこんなに高速になっているんでしょうか...?



終わりに

この結果は2017年5月時点で、実行環境に表記した内容での計測結果です。

ロジックや、環境次第では 異なる結果 になる可能性も、十分にありますので注意してください。