うさぎのメモ帳

performance.mark() と performance.measure() が少し扱いづらい

2019年10月18日 - 2019年10月19日

JSで処理速度を計測するときに performance.mesure() を使うように成って間もないですが、これが少し扱いづらい。

performance.mark('a:start') // a:start でマークをして
// 何らかの処理
performance.mark('a:end') // a:end でマークをして
performance.measure('measure a:start to a:end', 'a:start', 'a:end') // a:start から a:end までの時間を計測

performance.mark('b:start') // b:start でマークをして
// 何らかの処理
performance.mark('b:end') // b:end でマークをして
performance.measure('measure b:start to b:end', 'b:start', 'b:end') // b:start から b:end までの時間を計測

console.log(performance.getEntriesByType('measure')) // PerformanceMeasure[] を出力

// [
//   {
//     duration: 0.014999999621068127
//     entryType: "measure"
//     name: "measure a:start to a:end"
//     startTime: 14.714999999341671
//   }, ...
// ]

特定の場所に名称でマークをして、範囲を指定して測定できるのは便利ですが、ひとつずつの処理の時間を計りたいことのほうが多いと思いました。

そこで例えばuseP()というパフォーマンスを計測するための関数があって、以下のように使えたら便利だなと。

const p = useP()

p.mark()
// 何らかの処理
p.measure('Time A')

p.mark()
// 何らかの処理
p.measure('Time B')

p.log() // console.log で出力
p.table() // console.table で出力

本当はp.mark()の時点で計測名をつけたほうが分かりやすいのですが、あまり元の仕様を崩したくはないので。
この仕様なら元の関数から名前の引数がなくなったと考えるだけで済みます。

ので、以下のようにつくりました。

const useP = () => {
  performance.clearMarks()
  performance.clearMeasures()

  let counter = 0

  const mark = () => {
    performance.mark(String(counter))
  }

  const measure = (name) => {
    performance.measure(name, String(counter))
    counter += 1
  }

  const log = () => {
    console.log(performance.getEntriesByType('measure'))
  }

  const table = () => {
    console.table(performance.getEntriesByType('measure'))
  }

  return {
    mark,
    measure,
    log,
    table
  }
}

window.useP = () => { ...で定義しておいて先に読み込んでおけば全体で使うこともできます。

おまけ

最近 Vue 3 の書き方 (Composition API RFC) にものすごく影響を受けてて、useName()の関数を作っていく書き方がマイブーム。使うぞ!っていうのがわかりやすい。
Composition API と違ってwatchcomputedができないことを念頭におけば、比較的複雑な Vanilla JS 案件もuseNAME()で組むことができました。