JavaScript 関数のパフォーマンスを測定するさまざまな方法の比較

JavaScript 関数のパフォーマンスを測定するさまざまな方法の比較

概要

関数の実行にかかる時間を測定することは、ある実装が他の実装よりもパフォーマンスが優れていることを証明する良い方法です。これは、何らかの変更後にパフォーマンスが影響を受けていないことを確認したり、ボトルネックを追跡したりするのにも適した方法です。

優れたパフォーマンスは優れたユーザー エクスペリエンスに貢献し、優れたユーザー エクスペリエンスはユーザーの再訪につながります。ある調査によると、オンライン消費者の 88% は、パフォーマンスの問題によりユーザー エクスペリエンスが悪くなった後に戻ってくる可能性が低くなります。

そのため、コード内のボトルネックを特定し、改善を測定することが可能になります。特にブラウザ用の JavaScript を開発する場合は、シングルスレッド言語であるため、記述する JavaScript の各行が DOM をブロックする可能性があることに注意してください。

この記事では、関数のパフォーマンスを測定する方法と、関数から得られる結果をどのように扱うかについて説明します。

パフォーマンス.now

パフォーマンス API は、関数 performance.now() を通じて DOMHighResTimeStamps へのアクセスを提供します。この関数は、ページが読み込まれてから経過した時間を、最大 5μs の小数点以下の精度でミリ秒単位で返します。

したがって、実際には、2 つのタイムスタンプを取得して変数に格納し、最初のタイムスタンプから 2 番目のタイムスタンプを減算する必要があります。

定数 t0 = パフォーマンス.now();
(i = 0 とします; i < array.length; i++) {
  //コード
}
定数 t1 = パフォーマンス.now();
console.log(t1 - t0, 'ミリ秒');

Chrome出力

0.6350000001020817「ミリ秒」

Firefox 出力

1ミリ秒

ここで、Firefox の結果が Chrome とはまったく異なることがわかります。これは、Firefox バージョン 60 でパフォーマンス API の精度が 2 ミリ秒に低下したためです。

パフォーマンス API は、タイムスタンプを返すだけでなく、ナビゲーション タイミング、ユーザー タイミング、リソース タイミングを測定できるなど、多くの機能を提供します。より詳しい説明については、この記事をご覧ください。

ただし、私たちのユースケースでは、単一の関数のパフォーマンスのみを測定したいので、タイムスタンプで十分です。

それはDate.nowと同じではないですか?

ここで、あなたはこう考えているかもしれません: Date.now でも同じことができるのに。

はい、可能ですが、欠点もあります。

Date.now は、Unix エポック ("1970-01-01-01T00:00:00:00Z") からの時間をミリ秒単位で返し、システム クロックに依存します。これは、正確性が低下するだけでなく、必ずしも増加するわけでもないことを意味します。 WebKit エンジニア (Tony Gentilcore) は次のように説明しました。

あまり考慮されていないかもしれませんが、システム時間に基づく日付も、実際のユーザー監視には理想的ではありません。ほとんどのシステムでは、定期的に時間を同期するデーモンが実行されます。通常、時計は 15 ~ 20 分ごとに数ミリ秒調整されます。この割合では、10 秒間隔の約 1% が不正確になります。

コンソール.time

API の使い方は本当に簡単で、測定したいコードの前に console.time を置き、測定したいコードの後に​​ console.timeEnd を置き、同じ文字列パラメータで関数を呼び出すだけで、ページ上で同時に最大 10,000 個のタイマーを使用できます。

精度はパフォーマンス API と同じですが、これもブラウザに依存します。

コンソールで時間を指定して実行します。
(i = 0 とします; i < array.length; i++) {
  //コード
}
コンソールのtimeEnd('テスト');

これにより、以下に示すように、人間が読める出力が自動的に生成されます。

Chrome出力

テスト: 0.766845703125ms

Firefox 出力

テスト: 2ms - タイマー終了

ここでの出力も、パフォーマンス API と非常によく似ています。

console.time の利点は、2 つのタイムスタンプの差を手動で計算する必要がないため、使いやすいことです。

時間精度を短縮

上記の API を使用して異なるブラウザで関数を測定すると、結果が異なる場合があります。

これは、ブラウザがタイミング攻撃やフィンガープリント攻撃からユーザーを保護しようとしているためです。タイムスタンプが正確すぎると、ハッカーがそれを使用してユーザーを識別する可能性があります。

たとえば、Firefox などのブラウザは、精度を 2 ミリ秒 (バージョン 60) に下げることでこれを防止しようとします。

注意事項

これで、JavaScript 関数の速度を測定するために必要なツールが手に入りました。ただし、避けたほうがよい落とし穴もいくつかあります。

分割して征服する

いくつかの結果をフィルタリングするときに何かが遅いことに気付きましたが、ボトルネックがどこにあるかわかりません。

コードのどの部分が遅いかを推測するのではなく、これらの関数を使用して測定します。

これを突き止めるには、まず、遅いコード ブロックの周囲に console.time ステートメントを配置します。次に、さまざまな部分のパフォーマンスを測定し、ある部分が他の部分よりも遅い場合は、そのパスをたどり続け、ボトルネックが見つかるまで、そのたびに深く掘り下げていきます。

これらのステートメント間のコードが少ないほど、興味のないものを追跡する可能性が低くなります。

入力値に注意してください

実際のアプリケーションでは、特定の関数の入力値が大きく変化する可能性があります。単に任意のランダム値に対して関数の速度を測定しても、実際に使用できる貴重なデータは得られません。

必ず同じ入力値でコードを実行してください。

関数を複数回実行する

配列を反復処理し、各配列値に対して何らかの計算を実行し、結果の配列を返す関数があるとします。 forEach と単純な for ループのどちらがより効率的かを知りたい。

関数は次のとおりです。

関数testForEach(x) {
  console.time('test-forEach');
  定数res = [];
  x.forEach((値, インデックス) => {
    res.push(値 / 1.2 * 0.1);
  });

  console.timeEnd('test-forEach')
  res を返します。
}

関数testFor(x) {
  console.time('テスト用');
  定数res = [];
  (i = 0; i < x.length; i++) の場合 {
    res.push(x[i] / 1.2 * 0.1);
  }

  console.timeEnd('テスト用')
  res を返します。
}

次のようにテストできます:

const x = 新しい配列(100000).fill(Math.random());
テストごとに(x);
テスト対象x

上記の関数を Firefox で実行すると、次のような出力が得られます。

test-forEach: 27ms - タイマー終了

テスト対象: 3ms - タイマー終了

forEach は遅いように見えますよね?

同じ入力で同じ関数を 2 回実行するかどうか確認してみましょう。

テストごとに(x);

テストごとに(x);

テスト対象x

テスト対象x

test-forEach: 13ms - タイマー終了

test-forEach: 2ms - タイマー終了

テスト対象: 1ms - タイマー終了

テスト対象: 3ms - タイマー終了

forEach テストを 2 回目に呼び出すと、for ループと同じように実行されます。初期値が遅いことを考えると、いずれにしても forEach を使用する価値はないと思われます。

...複数のブラウザで

上記のコードを Chrome で実行すると、結果が突然違って見えます。

テスト forEach: 6.156005859375 ミリ秒

テスト forEach: 8.01416015625 ミリ秒

テスト: 4.371337890625ms

テスト: 4.31298828125ms

これは、Chrome と Firefox には異なるタイプのパフォーマンス最適化を備えた異なる JavaScript エンジンがあるためです。これらの違いを認識しておくとよいでしょう。

この場合、Firefox は同じ入力に対して forEach の使用をより適切に最適化します。

for はどちらのエンジンでもパフォーマンスが向上するため、 for ループを使用することをお勧めします。

これは、複数のエンジンで測定する必要がある理由を示す良い例です。 Chrome のみを使用して測定すると、forEach は for に比べてそれほど悪くないと結論付けられるかもしれません。

CPUのスロットル

これらの数字は高くないように見えます。通常、開発マシンは、Web サイトが表示される平均的な携帯電話よりもはるかに高速であることに注意してください。

これがどのようなものかを知るために、ブラウザには CPU パフォーマンスを調整できる機能があります。

これにより、10 ミリ秒または 50 ミリ秒がすぐに 500 ミリ秒に変わりました。

相対的なパフォーマンスの測定

これらの生の結果は、実際にはハードウェアだけでなく、CPU や JavaScript スレッドの現在の負荷にも依存します。次回 PC を再起動したときに数値が大きく変わる可能性があるため、測定値の相対的な改善に注目してください。

要約する

この記事では、パフォーマンスを測定するために使用できる JavaScript API と、それらを「現実世界」で使用する方法について説明しました。単純な測定には console.time を使用する方が簡単だと思います。

フロントエンド開発者の多くは、パフォーマンスが収益に直接影響を与えるにもかかわらず、日常的にパフォーマンスについて十分に考えていないように感じます。

上記は、JavaScript 関数のパフォーマンスを測定するさまざまな方法の比較の詳細な内容です。JavaScript 関数のパフォーマンスの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JSパフォーマンス最適化の実装方法と利点
  • js関数のパフォーマンス比較方法
  • JavaScript for ループのパフォーマンス テストの例
  • Java でよく使用されるいくつかの JSON ライブラリの詳細なパフォーマンス比較
  • 3つのJavascript文字列連結方法とパフォーマンスの比較
  • 高性能なJavaScriptを実装する際に注意すべきこと
  • 画像の遅延読み込みとページパフォーマンスの最適化を実現するネイティブJS
  • JavaScript パフォーマンス改善パス (推奨)
  • JavaScript配列の進化とパフォーマンス分析

<<:  MySQL ストレージ エンジンの基礎

>>:  nginx がどのようにして高いパフォーマンスとスケーラビリティを実現するのかを深く理解する

推薦する

NavicatでMySqlスケジュールタスクを作成する方法の詳細な説明

Navicat で MySql スケジュールタスクを作成する詳細な説明イベントは、MySQL が特定...

Dreamweaver8を使用してウェブサイトのファイルをチェックして整理する方法

Dreamweaver8 を使用して独自の Web サイトを作成する目的は何ですか?インターネットに...

シェアしたい絶妙なApple風無料アイコン素材18セット

Apple マグカップのアイコンと追加機能 HD ストレージボックス – アドオンパックセイバースノ...

VMware + Ubuntu18.04 による Hadoop クラスタ環境の構築に関するグラフィック チュートリアル

目次序文VMware クローン仮想マシン (準備、3 台の仮想マシンのクローン、1 台のマスター、2...

MySQL は SQL ステートメントの最新のレコードをクエリします (最適化)

最悪の選択肢は、結果を時間順に並べ替えて最初のものを取ることです。 *から選択 ここで、create...

DockerはRedis5.0をビルドし、データをマウントします

目次1. 永続データの簡単なマウント2. DockerFileでイメージをビルドし、設定ファイルを指...

Nginx 構成検出サービスのステータスを実装する方法

1. チェックステータスモジュールがインストールされているかどうかを確認します。 [root@loc...

CSS の一部のプロパティの前には「*」または「_」が付きます。

CSS の一部のプロパティの前には「*」または「_」が付きます。さまざまなブラウザを識別する例えば...

WeChat アプレット計算機の例

WeChatアプレット計算機の例、参考までに、具体的な内容は次のとおりです。インデックス.wxml ...

DockerにRedisをインストールし、パスワードを設定して接続する方法

Redis は分散キャッシュ サービスです。キャッシュは、大規模システムの開発やパフォーマンスの最適...

小規模プロジェクトで Vue が点滅するのを防ぐ方法

まとめHTML: 要素と v-cloak CSS: [v-cloak]{表示: なし}プロセスページ...

axios リクエストのカプセル化に基づく Vue アプリケーションのサンプルコード

目次axiosとは何ですか? Axios リクエストタイプ? Axiosはデフォルトのカスタム構成を...

Vueはリストのシームレスなスクロールを実装します

この記事の例では、リストのシームレスなスクロールを実現するためのvueの具体的なコードを参考までに共...

HTML テーブルタグチュートリアル (19): 行タグ

<TR> タグの属性は、次の表に示すように、テーブル内の各行のプロパティを設定するために...

MySQL データベースは XA 仕様をどのように実装しますか?

MySQL 一貫性ログMySQL データベースの電源が切れた場合、コミットされていないトランザクシ...