JavaScriptの処理がどれくらいかかっているのか調査する方法をご紹介します。スクリプトが重い気がする、処理速度を改善したい、などなどJavaScriptの速さを計ってみたい場合などに有用です。
特定のメソッド間で何ミリ秒かかってしまっているのか、やこのループにかなりの時間かかっているのではないか、などWebページのフォーマンス向上のために改善を考える道しるべとなります。
是非、覚えて実践でも活用してみてくださいね。
あ、補足ですが、このーページをChromeのデベロッパーツールを開きながら読むことを推奨します。デベロッパーツールのコンソールタブを開いてみてみてください。
performanceプロパティを使う方法
JavaScriptのWindowインターフェースにはperformanceというプロパティがあります。このプロパティに含まれるnow()
メソッド、mark()
メソッド、measure()
メソッドをそれぞれ使って、JavaScriptの処理速度を計測することが出来ます。
①window.performance.now()メソッドで計測する方法
(window.)performance.now()メソッドはマイクロ秒精度の結果を取得出来ます。返される値の単位はミリ秒になりますが、「1960.199999999255ミリ秒」のように小数点第十二位まで確認することが可能です。
console.log( performance.now() ); // window.は省略可
Google Chromeをお使いの方はこのページ上で(F12キーで)デベロッパーツールを開き、コンソールログを確認してみてください。「performance.now():1960.199999999255」のようなログが表示されますね。
このperformance.now()
メソッドは、読み込み開始からのミリ秒を返すので、これ単体では特定のメソッドの処理時間を計ることが出来ませんね。
そこで、performance.now()
メソッドで自作コードを挟んでやり、前後の差を見て処理に何秒かかったのかを知るという結構原始的な方法です。
例えば、
let beforeMethod = performance.now();
let sampleFunc = function(){
let intTest = 0;
for(let i=0; i<1000000; i++) { // 例として1,000,000回10を足してみましょう
intTest += 10;
}
console.log('intTest : ' + intTest);
}();
let afterMethod = performance.now();
console.log("1,000,000回10を足す処理時間は、" + (afterMethod - beforeMethod) + "ミリ秒です");
先ほどと同様にGoogle Chromeのデベロッパーツール上でコンソール画面を確認してみてください。「1,00,000回10を足す処理時間は、0.19999998807907104ミリ秒です」のような感じで出ていませんでしょうか??
この方法は計測したいロジック部分をperformance.now()
メソッドで挟んで差分を見て処理時間を算出する方法です。最もシンプルで分かりやすいかと思います。ただし、少し入り組んだ大規模なプロジェクトでは少々手間がかかることがありそうですね。
そこで次の方法を取り入れることで複雑な計測を一元的に集約しやすくすることが出来ます。
②window.performance.mark()、window.performance.measure()を併用する方法
performance.mark()
メソッドがperformance.now()
メソッドと大きく異なる点は、「指定した名前でタイムスタンプを作成」出来るという点です。
どういうことかというと、performance.now()
には"命名"という概念がなく、単純に時間(ミリ秒)を返すだけでした。それに対してperformance.mark()
はブラウザーのパフォーマンスエントリーバッファーへ名前とともに時間(ミリ秒)を登録しておくことが出来るのです。
このmark()
メソッドの最大のメリットは複数のポイントをマークすることが出来、後々そのポイントの指定をmeasure()
メソッドの引数を変更するだけで観測点を変えられるという点です。
なんだかんだ説明するよりも実際にどのようなコードを書けばよいかご覧になった方が早いかと思います。
performance.mark('pfm-mark-01'); // (1)1つ目の計測点のマーキング
let sampleFunc02 = function(){
let v = 0;
for(let i=0; i<1000000; i++) { // 例として1,000,000回10を足してみましょう
v += 10;
}
console.log('v : ' + v );
}();
performance.mark('pfm-mark-02'); // (2)2つ目の計測点のマーキング
let sampleFunct03 = function(){
let w = 0;
for(let i=0; i<10000000; i++) { // 例として10,000,000回10を足してみましょう
w += 10;
}
console.log('w : ' + w );
}();
performance.mark('pfm-mark-03'); // (3)3つ目の計測点のマーキング
performance.measure( //
'pfm-measure', // バッファの名前を指定してあげる
'pfm-mark-01', // 開始点(1)
'pfm-mark-02' // 終了点(2)
);
performance.measure(
'pfm-measure-02', // バッファの名前を指定してあげる
'pfm-mark-02', // 開始点(2)
'pfm-mark-03' // 終了点(3)
);
// 結果の取得
const results = performance.getEntriesByName('pfm-measure'); // バッファの名前から結果を取得(1)~(2)
const results2 = performance.getEntriesByName('pfm-measure-02'); // バッファの名前から結果を取得(2)~(3)
// ミリ秒の差分はresults[0]のdurationプロパティで参照すること
console.log("sampleFunc02の処理時間 : " + results[0].duration + "ミリ秒"); // (1)~(2)
console.log("sampleFunc03の処理時間 : " + results2[0].duration + "ミリ秒"); // (2)~(3)
計測を開始したい場所に例えばperformance.mark('pfm-mark-01');
のように「pfm-mark-01」という名前を使って観測点を設置します。
このマーキングは複数設置できるのでお好みの位置に、performance.mark('pfm-mark-02');
を設置しても大丈夫です。1個目のマーキングとは名前を変えることを忘れないでくださいね。
観測終了点にはperformance.mark('pfm-mark-03');
を置き、準備は完了です。
最終的に処理速度の計測を行うには、
performance.measure(
'pfm-measure-02', // バッファの名前を指定してあげる
'pfm-mark-02', // 開始点(2)
'pfm-mark-03' // 終了点(3)
);
// 結果の取得
const results = performance.getEntriesByName('pfm-measure');
上記のようにperformance.measure()
メソッドを使って処理時間のミリ秒を取得出来ます。
measure()
メソッドの第一引数には、バッファとして指定したい名前を入れ(分かりやすければ何でも大丈夫です)、第二引数には開始の観測点の名前を、第三引数には終了の観測点の名前をセットします。
全体的なミリ秒の取得は、上記のmeasure()
メソッドの後にperformance.getEntriesByName()
メソッドを使って行います。忘れがちなのでmeasure()
の後でgetEntriesByName()
で実測値を得る、というように覚えておきましょう。
consoleオブジェクトを使う方法
window.consoleオブジェクトを使って時間を計測する方法もあります。
使用するメソッドは、
console.time()
メソッドconsele.timeLog()
メソッドconsole.timeEnd()
メソッド
の3種類で可能です。
console.time('cons-time') // 計測開始はtime('任意の名前・識別用');
let sampleFunc04 = function(){
let x = 0;
for(let i=0; i<100000000; i++) { // 例として100,000,000回10を足してみましょう
x += 10;
}
console.timeLog('cons-time'); // 途中経過を出したい場合はtimeLog('最初に設定した名前');
console.log('x : ' + x );
}();
console.timeEnd('cons-time'); // 終了時、time('最初の名前')~timeEnd('最初の名前')までのミリ秒
console.time()
メソッドでは、console.log()
で出力処理をしなくても自動的にコンソール上にミリ秒が出力されます。
一見便利そうですが、応用が利かない(プログラム上で計算が出来ない等)ので、performance.now()
やperformance.mark()
、performance.measure()
を用いることをおすすめします。が、単純に実行時間を知りたいだけであれば、この限りではありません。