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 がどのようにして高いパフォーマンスとスケーラビリティを実現するのかを深く理解する

推薦する

Linuxでpyファイルを直接実行する方法

1. まずファイルを作成します(ファイルを配置するディレクトリにcdします) myTest.py を...

HTML テーブル マークアップ チュートリアル (16): タイトルの水平方向の配置属性 ALIGN

デフォルトでは、表のタイトルは水平方向に中央揃えされます。ALIGN 属性を使用して、タイトル テキ...

ネイティブJSでマウススライドによる愛の拡散効果を実現

この記事では、マウスをスライドすると愛が広がる js 特殊効果を紹介します。効果は次のとおりです。 ...

Nginx ベースの HTTPS ウェブサイトを設定する手順

目次序文:暗号化アルゴリズム: 1. HTTPS の概要2. NginxはHTTPSウェブサイト設定...

Vue で手ぶれ補正とスロットリングを使用する方法

目次序文コンセプト安定意味使用シナリオコードVueでの使用スロットリング意味使用シナリオコードVue...

Docker Compose のインストールと使用手順

目次1. Docker Compose とは何ですか? 2. Docker Composeのインスト...

CSS3 で六角形の境界線を実装するサンプルコード

一番外側の boxF は 120 度回転し、2 番目の boxS は -60 度回転し、3 番目の ...

Windows プラットフォームでの MySQL のインストールと設定方法と注意事項

2.1、msiインストールパッケージ2.1.1、インストール特に重要なのは、インストール前に、元の ...

Tomcat の maxPostSize 設定に関する問題と注意事項

1. maxPostSize を設定する理由は何ですか? tomcat コンテナには送信データのサイ...

テキストエリアのテキストをHTMLに変換する方法、つまり復帰改行について

説明: テキストエリアの値の改行を新しい行に変更しますコードをコピーコードは次のとおりです。 <...

Linux のよく使うコマンドの使い方を詳しく解説(第 2 回)———— テキストエディタのコマンド vi/vim

vi/vim の紹介どちらもマルチモード エディターです。違いは、vim が vi のアップグレー...

tomcat+nginx を使用してマルチアプリケーション デプロイメントを実装するためのサンプル コード

目次マルチアプリケーションの展開1-Tomcat 構成1.1- プロジェクト構成1.2-サービス構成...

Linux で特定のプログラムを見つけるための whereis の例の詳細な説明

Linuxは特定のプログラムを見つけますwhereis コマンドは主にプログラム ファイルを検索し、...

入力タイプの制限(複数の方法)

1. 入力・貼り付けできるのは中国語のみ<input onkeyup="value=...

Web フロントエンドのパフォーマンス最適化の詳細説明: リソースのマージと圧縮

2つの目的のためのリソースの結合と圧縮httpリクエストの数を減らす要求されたリソースのサイズを縮小...