Webアプリケーションのパフォーマンスは、特にWeb開発の速度が直接ユーザーのチャーンにつながります。プロのフロントエンド開発者として、パフォーマンスの最適化に注意を払う必要があります。リクエストの削減、CDNの使用、ブロッキングレンダリングの執筆の回避など、多くの従来のWebパフォーマンス最適化方法は、今日でも有効です。ただし、ますます多くのWebアプリケーションがJavaScriptを使用するにつれて、コード効率の検証が重要になりました。
機能的であるが、効率的ではなく、改善を計画していると疑っている関数があるとします。この仮定を証明する方法は? JavaScript機能パフォーマンスをテストするためのベストプラクティスは何ですか?一般的に、最良の方法は、組み込みperformance.now()
関数を使用して、機能が実行される前後の時間を測定することです。この記事では、いくつかの一般的な落とし穴を避けるために、コードの実行時間とトリックを測定する方法について説明します。
キーポイント
performance.now()
関数を使用して、機能が実行される前後の時間を測定することです。 now()
という関数を提供します。これにより、渡された時間の正確な説明が提供され、組み込みDOMHighResTimeStamp
オブジェクトよりも正確になります。 Date
performance.now()
関数実行時間を1回だけ測定するのは一般的なエラーです。実行時間はさまざまな要因に基づいて大きく異なるため、関数を繰り返して平均時間または中央値を計算することをお勧めします。 高解像度時間APIは、 オブジェクトを返す
と別の を呼び出して、その値を変数
しかし、この場合、関数を呼び出すのにかかる時間と、その出力をコンソールに送信して印刷するのにかかる時間を測定します。これらの2つの操作がどれくらいかかるかはわかりません。組み合わせ時間のみを知っています。さらに、送信と印刷に必要な時間は、ブラウザや当時のブラウザで何が起こっているかによって大きく異なります。 同様に、実行時間がどのように割り当てられるかはわかりません。それは変動する割り当て、 トレイル#2 - 1回のみ測定 メインスレッドは、私たちが気づかない他のことを扱うのに忙しいです
トレイル#3 - 平均して過剰依存 前のセクションでは、何かを繰り返し、理想的には異なる入力を使用することが良い習慣であることがわかりました。ただし、さまざまな入力の問題は、実行時間が他のすべての入力よりもはるかに長くなる可能性があることを覚えておく必要があります。それでは、一歩下がって同じ入力を送信しましょう。同じ入力を10回送信し、毎回かかる時間を印刷するとします。出力は次のようになる場合があります: 初めて、その数は他の9回とはまったく異なることに注意してください。これは、ブラウザのJavaScriptエンジンがいくつかの最適化を行っており、ウォームアップが必要なため、おそらくそうです。これを避けることはほとんどできませんが、誤った結論を防ぐためにいくつかの良い救済策を考慮することができます。 1つの方法は、過去9回の時間平均を計算することです。もう1つのより実用的なアプローチは、すべての結果を収集し、中央値を計算することです。基本的に、これはすべての結果であり、中央の結果を選択します。これは、 何かを複数回測定して平均することは常に良い考えであることを学びました。さらに、最後の例では、平均ではなく中央値を使用する方が良いことがわかります。実際、関数の実行時間を測定するのに適した使用法は、いくつかの関数のどれがより速いかを理解することです。同じタイプの入力を取り、同じ結果を生成する2つの関数があると仮定しますが、内部的には異なる動作をします。文字列が他の文字列の配列に存在する場合、trueまたはfalseを返す関数が必要であると仮定しますが、これはケース非感受性です。言い換えれば、それは症例に依存しないため、 早期の一致があっても、 今どちらがより速いか見てみましょう。各関数を10回実行し、すべての測定値を収集することにより、これを行います。
[CodePenリンクはここに挿入する必要があります。外部Webサイトにアクセスできないため、提供できない] 正確に何が起こったのですか?最初の関数は3倍高速です。これは起こってはいけません! 説明は簡単ですが、微妙です。ブラウザのJavaScriptエンジンにおけるいくつかの低レベルの最適化の利点を
(上記のコンテンツと高度に複製されているため、FAQの部分は省略されています。キーポイントを保持してください。)now()
という関数を提供します。これは、現在の時間をミリ秒単位で反映する浮動小数点数であり、1000分の1ミリ秒まで正確です。個別に、この数値は分析にとってそれほど価値はありませんが、そのような2つの数値の違いは、時間が経過した時間を正確に説明できます。組み込みDOMHighResTimeStamp
オブジェクトよりも正確であることに加えて、「単調」でもあります。これは、簡単に言えば、システムの時間を定期的に修正するシステム(ラップトップオペレーティングシステムなど)の影響を受けないことを意味します。簡単に言えば、の2つのインスタンスを定義し、違いを計算することは、経過時間を表していません。 「単調」の数学的定義は、
(関数または量の場合)が変化し、それが減少しないか、増加しないように変化することです。それを説明する別の方法は、時計が前または後方に切り替える期間中にそれを使用することを想像することです。たとえば、あなたの国の時計がすべて1時間スキップして日光を最大化することに同意するとき。クロックがダイヤルされる1時間前にDate
インスタンスを作成したい場合、その後、別のDate
インスタンスが違いを見て、「1時間3秒123ミリ秒」のようなものが表示されます。 2つのインスタンスを使用すると、差は「3秒123ミリ秒と456789千分の1ミリ秒」になります。このセクションでは、このAPIについて詳しく説明しません。そのため、詳細を知り、使用している例をいくつか見たい場合は、高解像度の時間APIを発見した記事を読むことをお勧めします。高解像度の時間APIが何であるか、それをどのように使用するかを学んだので、潜在的な落とし穴に飛び込んでみましょう。しかし、これを行う前に、この記事の残りの部分に使用するという関数を定義しましょう。
Date
Date
この関数の実行は、次のように測定できます。
performance.now()
makeHash()
このコードをブラウザで実行する場合、次のようなものが表示されます。
function makeHash(source) {
var hash = 0;
if (source.length === 0) return hash;
for (var i = 0; i < source.length; i++) {
var char = source.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
var t0 = performance.now();
var result = makeHash('Peter');
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
<code>Took 0.2730 milliseconds to generate: 77005292</code>
[CodePenリンクはここに挿入する必要があります。外部Webサイトにアクセスできないため、提供できない] makeHash('Peter')
多分あなたはそれがどれほど遅いかを正確に知っているでしょう。ただし、各関数にI/Oが含まれない場合でも、複数の関数を実行することも同様に間違っています。たとえば、
console.log
呼び出し、またはfunction makeHash(source) {
var hash = 0;
if (source.length === 0) return hash;
for (var i = 0; i < source.length; i++) {
var char = source.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
toLowerCase()
toString()
もう1つの一般的な間違いは、測定を一度だけ行い、時間を要約し、その時間に基づいて結論を導き出すことです。さまざまな時点で、これは完全に異なる可能性があります。実行時間は、主にさまざまな要因に依存します
コンパイラのウォームアップ時間(たとえば、コードがbytecodeにコンパイルされる時間)
あなたのコンピューターのCPUは、ブラウザ全体を遅くする特定のもので忙しい
[CodePenリンクはここに挿入する必要があります。外部Webサイトにアクセスできないため、提供できない] var t0 = performance.now();
var result = makeHash('Peter');
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
function makeHash(source) {
var hash = 0;
if (source.length === 0) return hash;
for (var i = 0; i < source.length; i++) {
var char = source.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
performance.now()
が非常に便利な場所です。好きなように使用できる番号を取得できるためです。もう一度やり直してみましょうが、今回は中央値関数を使用します:var t0 = performance.now();
var result = makeHash('Peter');
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
トレイル#4 - 予測可能な順序で関数を比較します
Array.prototype.indexOf
を使用することはできません。これは次のような実装です:<code>Took 0.2730 milliseconds to generate: 77005292</code>
haystack.forEach
ループは常にすべての要素を横断するため、これが改善できることにすぐに気付きました。ループ用の古い古いものを使用して、より良いバージョンを書くようにしましょう。 var t0 = performance.now();
console.log(makeHash('Peter')); // 不好的主意!
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds');
var t0 = performance.now();
var name = 'Peter';
var result = makeHash(name.toLowerCase()).toString();
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
var t0 = performance.now();
for (var i = 0; i < 10; i++) {
makeHash('Peter');
}
var t1 = performance.now();
console.log('Took', ((t1 - t0) / 10).toFixed(4), 'milliseconds to generate');
haystack.forEach
performance.now()
を使用してJavaScriptで正確な実行時間を取得する方法を実証しようとしている間、私たちの直感が経験的な結果との結論の正反対であるベンチマークシナリオに出くわしました。ポイントは、より速いWebアプリケーションを書きたい場合、JavaScriptコードを最適化する必要があるということです。コンピューターは(ほとんど)生きているものであるため、予測不可能で驚くべきものです。コードの改善がより速い実行速度をもたらすことを知る最も信頼できる方法は、測定と比較です。どのコードが高速であるかはわかりません。同じことをする方法が複数ある場合、別の理由はコンテキストが重要であることです。前のセクションでは、26の他の文字列に文字列を探して、ケースに依存しない文字列検索を実行しました。他の100,000の文字列で文字列を探す必要があった場合、結論は完全に異なる可能性が高いでしょう。上記のリストは、より多くの落とし穴があるため、網羅的ではありません。たとえば、非現実的なシナリオを測定するか、JavaScriptエンジンでのみ測定を行います。しかし、より速く、より良いWebアプリケーションを書きたいと思うJavaScript開発者にとって、performance.now()
は巨大な資産であることは確かです。最後になりましたが、実行時間の測定は「より良いコード」の1つの次元のみが生成されることを覚えておいてください。メモリとコードの複雑さも考慮する必要があります。あなたはどうですか?この関数を使用してコードのパフォーマンスをテストしたことがありますか?そうでない場合、この段階でどのように進めますか?以下のコメントであなたの考えを共有してください。議論を始めましょう!
以上がJavaScript関数の測定&#x27;パフォーマンスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。