performance.now()技術仕様: 反応時間計測になぜサブミリ秒精度が必要か
MDN Web Docs記載のW3C High Resolution Time仕様をベースに、反応速度ツール製作者・Web開発者向けに精度と落とし穴を解説します。
performance.now()とは何か
Performance.now()はW3C High Resolution Time Level 2仕様で定義されたDOMHighResTimeStamp型の時刻取得APIです。 単位はミリ秒、戻り値はdouble(倍精度浮動小数点数)で、サブミリ秒の精度を表現できます。
値はtime origin(ドキュメント生成時刻)からの経過時間で、常に単調増加(monotonic)が保証されています。 システム時計を変更しても値が逆行することはありません。
Date.now()との違い
| 項目 | performance.now() | Date.now() |
|---|---|---|
| 精度 | サブミリ秒(0.005〜1ms) | ミリ秒整数 |
| 基準 | ドキュメント生成時刻 | UNIXエポック(1970-01-01) |
| 単調性 | 常に単調増加 | システム時計次第で逆行可 |
| 用途 | 経過時間測定 | 絶対時刻表示 |
Spectre対策で精度が切り下げられた歴史
2018年のSpectre/Meltdown脆弱性発覚を受け、各ブラウザはperformance.now()の精度を一時的に大幅に下げました。 ChromeはSharedArrayBuffer無効時に100μs(0.1ms)刻み、Firefoxは1ms刻みまで切り下げました。
現在はCross-Origin-Opener-PolicyとCross-Origin-Embedder-Policyを両方有効にしたcross-origin isolated環境でのみ、サブミリ秒精度(約5μs)が解禁されます。 反応速度ツールは数百msオーダーで動くため、デフォルトの100μs精度でも実用上問題ありません。
⚠️ JS時刻測定で取れない遅延
performance.now()がいくら高精度でも、人間が画面で見て反応するまでには以下の遅延が乗ります:
- requestAnimationFrame待ち: 60Hzなら最大16.6ms(次のフレーム)
- モニター応答時間: 一般5〜10ms / ゲーミング1ms
- マウスポーリングレート: 一般125Hz=8ms / ゲーミング1000Hz=1ms
- OS入力レイテンシ: 1〜5ms
- USB-HID処理: 1〜2ms
合計で20〜35msのオフセットが必ず乗ります。「他人との比較」には使えず、「自分の経時変化」にのみ意味があります。
反応時間計測の最小実装
let readyAt = 0;
button.onclick = () => {
const ms = performance.now() - readyAt;
console.log(`${Math.round(ms)} ms`);
};
// 緑表示と同時に
readyAt = performance.now();本ツール反応速度テストもこの構造です。緑への切替直後のperformance.now()を基準点とし、クリック時の差分をms表示します。
関連
- ・反応速度テスト本体
- ・FPS大会前ウォームアップ術
- ・加齢と反応時間の付き合い方
- ・マウステスト(入力遅延の事前チェック)