どの処理にどれだけ時間がかかっているのか・・・調べたいことってありますよね?
でも正しい計測方法を知っていないと精度が悪かったり余計な手間がかかってしまうかもしれません。
ということでJavaScriptでの本当に正しい処理時間の計測方法について紹介します。
このページの目次
Date.nowは時間計測に使ってはダメ!
JavaScriptには現在の時間をミリ秒で返してくれるDate.now関数が用意されています。
しかし、処理時間を計測するのにこの Date.now は使うべきではありません。
確かにこの関数を使えば次のように簡単に時間が計測できます。
1 2 3 4 5 6 7 8 9 10 11 |
/** 始まりの時間を記録 */ var start = Date.now(); for(var i = 0; i < 10000; i++){ for(var j = 0; j < 10000; j++); } /** 終わりの時間を記録 */ var end = Date.now(); console.log( '実行時間 = ' + (end - start) + 'ミリ秒' ); |
これは以外とよく使ってしまう方法ではないでしょうか。
僕自身もこういうやり方で時間を測っていたことがありました。
ですが Date.now を使うのは次のような点であまりいいことではありません。
- ミリ秒以下の精度で計測できない
- そもそも計測用の関数でない
精度がそもそもミリ秒までなのでそれ以下の精度で計測ができないというのが問題です。
じゃあ代わりに何を使えばいいのかというのが次で説明する本題です。
処理時間の計測には performance.now を使おう
処理時間を測るのに一番適しているのはperformanceインターフェースを使うことです。
これはパフォーマンス計測のためだけに用意された専用のAPIです。
そして現在の時間を取得するのに performance.now が使えます。
1 |
var now = performance.now(); |
使い方は Date.now 全く同じです。
この関数で返される時間の単位はミリ秒です。
しかし次のようにミリ秒の小数点以下まで表示されるのが Date.now との違い
1 |
8833.80 |
小数点以下がどの桁まで表示されるかはブラウザ次第です。
ですが間違いなくミリ秒以下の精度で時間を計測することが可能になります。
なのでこれを使うことで制度の高い計測が可能です。
例えば次が performance.now を使った計測のコード例
1 2 3 4 5 6 7 8 9 10 11 |
/** 始まりの時間を記録 */ var start = performance.now(); for(var i = 0; i < 10000; i++){ for(var j = 0; j < 10000; j++); } /** 終わりの時間を記録 */ var end = performance.now(); console.log( '実行時間 = ' + (end - start) + 'ミリ秒' ); |
これを実行してみるとコンソールには次のようにミリ秒以下までしっかり表示されます。
1 |
実行時間 = 680.800000031013ミリ秒 |
ただこれだと余計な桁まで表示されてしまうので少し見にくいです。
なので実際は次のようにミリ秒以下3桁くらいで丸めればいいと思います。
1 2 |
var time = (end - start).toFixed(3); console.log( '実行時間 = ' + time + 'ミリ秒' ); |
toFixed関数が指定した小数点以下の桁数で丸めるための関数です。
これで表示する時に3桁固定になります。
1 |
実行時間 = 740.200ミリ秒 |
以上が performance.now で時間計測する方法です。
performaceで時間計測をさらに便利にするには
performaceインターフェースでは時間を計測するのに便利な方法もあります。
それがmeasure関数とmark関数の2つを組み合わせるやり方です。
手順は大まかに書くと次の通り
- mark関数で計測開始地点にマーキング
1performance.mark('開始地点ID'); - mark関数で計測終了地点にマーキング
1performance.mark('終了地点ID'); - measure関数で開始から終了地点まで計測
12345performance.measure('計測名','開始地点ID','終了地点ID'); - getEntriesByName関数で計測時間取得
12const results = performance.getEntriesByName('計測名');const time = results[0].duration;
開始地点と終了地点にマーキングしてmeasure関数で後から計測するという方法です。
この説明だと分かりにくいと思うので具体的な例を出しましょう。
それが次のmark関数とmeasure関数を使った時間計測のコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** 計測開始 */ performance.mark('myPerfStart'); for(var i = 0; i < 10000; i++){ for(var j = 0; j < 10000; j++); } /** 計測終了 */ performance.mark('myPerfEnd'); /** 実際に計測 */ performance.measure( 'myPerf', 'myPerfStart', 'myPerfEnd' ); const results = performance.getEntriesByName('myPerf'); const time = results[0].duration; console.log( '実行時間 = ' + time + 'ミリ秒' ); |
一番最後当たりの getEntriesByName で計測名に結び付けられた複数の結果を取得しています。
その1つ1つの結果の duration プロパティに計測時間が入っています。
この方法だと無駄な変数が増えずスマートに書けるがメリットですね。
また好きな場所で時間計測できるのでデバッグに役立ちそうです。
補足 : PHPで処理時間を測るには・・・
もしWeb開発でPHPも使う、という人はPHPでの計測方法も知っておくと役立ちます。
PHPの場合、次の2関数を使うことで処理時間計測が可能
- time関数 : 処理時間を「秒」で計測
- microtime関数 : 処理時間を「マイクロ秒」で計測
測り方はJavaScriptの時と同じく、最後から最初の時間を引くだけです。
ちなみに詳しいやり方とかコード例は次でまとめた通り
PHPとJSは併用することが多いので、両方の時間計測の仕方を知っておいて損はありません。
ここまでのまとめ
ということで簡単にここまでをまとめると次の通り
- 時間計測にDate.nowは使うべきではない
精度が低く計測用でもないので使いにくいから
- 時間計測にはperformanceインターフェースを使う
performance.now関数から現在の時間をミリ秒以下で取得可能
またmark関数とmeasure関数を組み合わせるやり方もあり
ということでJavaScirptでの時間計測についてまとめてみました。
処理のボトルネックを測るのにこれから使っていこうと思います。
ではでは($・・)/~~~