処理時間の計測

アプリの起動がみょーに遅くて、どこで時間がかかっているのか調べたくなることってありますよね。私はしょっちゅうあります。そこで、JavaScriptで処理時間を計測する方法について調べました。メジャーな方法は次の2つのようです。

  • consoleオブジェクトのtime()/timeEnd()メソッドを使う
  • DateオブジェクトのgetTime()メソッドを使う

それぞれについて簡単に説明します。

consoleオブジェクトのtime()/timeEnd()メソッドを使う

console.time()メソッドによりタイマーを開始し、console.timeEnd()メソッドでタイマーを停止してその間の経過時間をミリ単位で取得します。引数はタイマーを選別する任意の名前になります。

console.time() — MDN
console.timeEnd() — MDN

使用例

console.time("timer_0");
alert("click!");
console.timeEnd("timer_0");

console.timeEnd()メソッドを実行すると経過時間がコンソールに出力されます。

ここで、戻り値がどうなっているのか気になって実験してみました。

実験

var a = console.time("timer_0");
alert("click!");
var b = console.timeEnd("timer_0");

console.log("a: " + a + ", b: " + b);

コンソール出力

timer_0: 7798.10693359375ms
a: undefined, b: undefined

戻り値はundefinedでした。取得した経過時間をUIに表示したりプログラムで使うことはできないみたいです。console()メソッドですから当然といえば当然ですかね。

DateオブジェクトのgetTime()メソッドを使う

Date()コンストラクタからインスタンス化した日付オブジェクト(new Date())のgetTime()メソッドは、1970年1月1日00:00:00からインスタンス化までの時間をミリ秒で返します。処理時間は、計測開始時と終了時にgetTime()メソッドでミリ秒を取得し、その差分をとることで得ることができます。
ちなみに、インスタンス化せずに直接Dateオブジェクトのnow()メソッドを使用してもgetTime()メソッドと同じ結果になります。ただしIE9未満で未サポートになっています。

getTime() — MDN

使用例

var stime = new Date().getTime();
for(var i=0, a=0; i<100000; i++) a += i;
var etime = new Date().getTime();

console.log("time: " + (etime - stime));

時間計測用のオブジェクトを作ってみた

処理時間を計測したいポイントが複数ある場合、各ポイントにgetTime()の実行と取得した値を格納するコードを埋め込み、最後にループ文などで差分を計算して表示する、というパターンになるかと思います。そこで時間計測用オブジェクトを作成してみました。

Script

var timeLog = (function() {
  var timeLog = {};
  var memory = [];
  timeLog.rec = function(comment) {
    memory.push({
      comment: comment || "",
      time: new Date().getTime()
    });
  };
  timeLog.show = function(flg) {
    var n = memory.length;
    if (n<=1) {
      console.log("Too few records");
      return;
    }
    var stime = memory[0].time, etime, delta, log, logs="";
    for (var i=1; i<n; i++) {
      etime = memory[i].time;
      delta = etime - stime;
      stime = etime;
      log = "[" + i + "] " + memory[i].comment + ": " + delta + "ms";
      logs += log + "\n";
      console.log(log);
    }
    if (flg) window.alert(logs);
  };
  timeLog.clear = function() {
    memory.length = 0;
  };
  return timeLog;
})();

使用例

timeLog.rec("start");
for(var i=0, a=0; i<100000; i++) a += i;
timeLog.rec("一回目の処理");
for(var i=0, a=0; i<1000000; i++) a += i;
timeLog.rec("二回目の処理");
for(var i=0, a=0; i<10000000; i++) a += i;
timeLog.rec("最後の処理");

timeLog.show();

コンソール出力

[1] 一回目の処理: 9ms
[2] 二回目の処理: 33ms
[3] 最後の処理: 193ms

一連の処理をまとめただけなのでその必要性が微妙なのですが、使用感はすっきりさわやかです。また、show()の引数にtrueなどを渡して呼び出すとアラートダイアログを表示します。release版のapkなどで確認する場合に使えると思います。