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

  • 23
    いいね
  • 0
    コメント

概要

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

実行環境

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月時点で、実行環境に表記した内容での計測結果です。
ロジックや、環境次第では 異なる結果 になる可能性も、十分にありますので注意してください。