【2021年版】ブラウザ別!JavaScriptでの繰り返しはどれが最速なのか?

JavaScript

こんにちは。
同じような処理を繰り返すときにつかうfor文。
JavaScriptの進化とともに、いろいろな書き方が増えてきました。

当初、JavaScriptは簡単な動きのあるWebページを実現するために作られた単純なプログラミング言語だったのですが、現在はフロントエンドアプリの開発だけでなく、バックエンドの開発にも使われるようになっています。
そのような分野では『処理速度』も大切な要素です。
そこで、この記事では、4つのfor文について処理速度を比較し、最速の繰り返し処理を検証してみました。
JavaScriptの繰り返し処理と処理速度について参考になるはずです。

測定方法

処理速度の測定は、処理の前と後のperformance.now()を用いて、その差を処理時間とする単純な方法を用いました。

const start = performance.now();
// 計測をする処理…
const end = performance.now();
console.log(end - start); //実行時間をコンソールに表示

計測をする処理は以下のように行い、5回測定して最大値と最小値を除外した3つの値の平均を結果としました。

  • あらかじめ、0から9999999までの1000万個の数字を配列に格納
  • その数字を順番にすべて足し合わせる

測定に使うarrayは以下のように設定しました。

let array = [];

for (var i=0; i<10000000; i++) {
  array[i] = i;
}

また、ブラウザは

  • Chrome 90.0.4
  • Firefox 88.0.1
  • Safari 14.1

を使用しました。

単純なfor文

まず、単純なfor文です。

for (let i=0; i <array.length; i++) {
  sum += array[i];
}

ここで配列arrayの要素を順番に取り出して、変数sumに足し合わせていきます。

for in文

for in文はオブジェクトの中身(プロパティという)を取り出して繰り返し処理を行います。
基本形は

for ([変数] in [オブジェクト]) {
    // 繰り返し実行する処理;
}

となります。
単純なfor文と比べると内容が理解しやすい読みやすいコードになります。

今回使用する配列もオブジェクトになりますので、

for (const s in array) {
  sum += s;
}

とやってしまいたくなりますが、こうすると結果は期待とは違うものになります。
というのも、sにはオブジェクトのプロパティがはいるので、数字ではなく文字として処理されます。
そのため、"012345678910111213141516171819202122......"という文字列結合の結果が得られることになります。

そこで、今回は、その文字列を数字に置き換えて計算するようにしました。

for (const s in array) {
  let v = Number(s);
  sum += v;
}

ひとつ余計な処理が入るので時間がかかりそうな予感がします。

for of文

for of文は、反復可能なオブジェクト(JavaScriptではiterableという)に対して繰り返し処理をするものです。
反復可能なオブジェクトについては説明を省きますが、反復処理(=繰り返し処理)時に、返す値などの動作が定義されたオブジェクトと思ってください。
なお、今回使用した配列は反復可能なオブジェクトです。

for of文の基本形は

for ([変数] of [反復可能なオブジェクト]) {
    繰り返し実行する処理;
}

となり、for in文と変わりません。
しかし、実際の処理内容は少し変わってきます。

for (const v of array) {
  sum += v;
}

繰り返し処理時に返される値が決まっているので、for in文で使用した置き換えが不要になります。

Array.forEach文

配列はオブジェクトですので、プロパティだけでなく、配列操作に必要なメソッドも持っています。
forEach()メソッドはそのひとつで、繰り返し処理を行います。
基本形は

const array = [配列の定義];

array.forEach( value => {
    // 配列の要素ごとに繰り返し実行する処理;
});

となります。
アロー関数を使っていますが、通常の関数表記も使えます。

今回の場合は、

array.forEach(v => {
  sum += v;
});

となります。
for in文と同じく単純でわかりやすいです。

結果

結果は以下の表のようになります(数値はミリ秒)。
各ブラウザで最速だった数値は、太文字にしてあります。

forfor infor offorEach()
Chrome2552624351357
Firefox343744525739
Safari1115734127298

まず、ブラウザによってこんなに結果が違うことに驚きます。
例えば、Firefoxは他の2つのブラウザに比べて高速ですが、for in文に関しては桁違いに遅いです。

それでも、単純なfor文が各ブラウザ共通で最高速です。
また、配列のforEach()メソッドが、どのブラウザでも、単純なfor文と変わらない速さであることは意外でもありました。
しかし、forEach()メソッドは配列オブジェクトのメソッドなので、配列以外の繰り返し処理には使えません。
用途が限られてしまうのが気になるところです。

「型指定した for」文

JavaScripitは、型付けの弱いプログラミング言語です。
便利な反面、予想もしない動きから不具合の原因になることもあります。
また、型が動的に決められる分だけ処理時間がかかります。

つまり、変数に対して型を指定すれば処理が速くなると考えられます。
そこで、今回for文で使用した処理を以下のようにしてみました。

for (let i=0; i<array.length; i=(i+1)|0) {
  sum += array[i];
}

単純なfor文との違いは、i++の部分がi=(i+1)|0として変数iが明確に数字であることを指定してあります。
こうすることによって処理が速くなると期待できます。

結果は以下のようになりました(単位は同様にミリ秒です)。

単純なfor型指定したfor
Chrome225229
Firefox3438
Safari111100

ほどんど変わりません。

最近はブラウザの改良が進み、この程度の高速化は対応済みなのかもしれません。

まとめ

本記事では、JavaScriptの繰り返し処理であるfor文について、単純なfor文、for in文、for of文、配列のforEach()メソッドの処理速度を比較しました。
結果は、単純なfor文が最も高速であるというものでしたが、用途が限られるものの、配列のforEach()for文と同程度の処理速度を示しました。

また、ブラウザによってかなり異なる結果が得られました。
ブラウザの進化は日進月歩で、今回のような単純な処理の場合、型指定程度で処理速度は変わらないという結果がそれを示しているかと思います。
処理速度を厳しく求められる場面では、実際に使用するブラウザで確認する必要があるかと思います。

またJavaScriptでよく用いられるのが、「即時関数」です。
初心者は以下の記事も併せて読むことで、より理解を深められるかと思います。

初心者でもわかる!JavaScriptで即時関数を使う理由
こんにちは。フロントエンドの開発といえばJavaScript。ただ、JavaScriptの関数には、通常の関数定義以外にも、関数リテラル、無名関数、アロー関数などいろいろな種類があって初心者が戸惑うポイントでもあります。ちょっと強引な言...

最後までお読みいただきありがとうございました。

コメント

タイトルとURLをコピーしました