手軽屋
ツール一覧

タブ切替・バックグラウンドでタイマーが正確な理由

終了時刻方式・Page Visibility API・setIntervalのスロットリング

1. 古いタイマー実装が遅れる理由

素朴な実装では「setInterval(fn, 1000)で1秒ごとに残り時間を1減らす」というカウントダウン方式を使います。これは画面を見ている間は正確ですが、ブラウザが別タブをアクティブにすると問題が起きます。Chrome・Firefox・Safariはバックグラウンドタブの JavaScript タイマーの実行頻度を制限(スロットリング)するため、1秒間隔のはずが10秒〜1分以上に間引かれ、結果として残り時間が大幅に遅れます。

2. Page Visibility APIによるスロットリング

Page Visibility APIは2013年にW3C勧告となった標準仕様で、document.visibilityState("visible"/"hidden")でタブの可視性を取得できます。ブラウザはタブが hidden になると CPU・電池消費を抑えるためタイマー間隔を1秒以上に制限します。Chrome 88以降ではバックグラウンドタブの setTimeout/setInterval の最小間隔が1分まで延長される強化スロットリングが導入されています(Tab Throttling)。

3. 終了時刻方式(end-time based)の設計

手軽屋のタイマーは「残り時間を1秒ずつ減らす」のではなく、「終了時刻(Unix時間ミリ秒)を記録し、再描画のたびに Date.now() との差分から残り時間を計算する」方式を採用しています。終了時刻は記録した瞬間に決まるので、再描画間隔がどれだけ間引かれても、再びアクティブになった時点で正確な残り時間を表示できます。スロットリングは表示更新の頻度を下げますが、実時間の進行は止められません。

4. ストップウォッチの累積方式

ストップウォッチも同様で「開始時刻+累積ミリ秒」の方式を使います。スタートで開始時刻を記録、ストップで「現在時刻−開始時刻」を累積に加算してリセット、再スタートで開始時刻を更新。この設計だとタブを切り替えても、PC を一時的にスリープしても、復帰後に正確な経過時間を表示します。setInterval のたびに変数を増やす方式とは根本的に違います。

5. PCスリープ・スマホロック時の挙動

ノートPCを閉じる・スマホを画面ロックすると、OS自体がブラウザのプロセスを一時停止することがあります。この場合は JavaScript が完全に停止するため、終了音は鳴りません。しかし復帰した瞬間に Date.now() が現在時刻を返すので、画面表示は正確な残り時間(マイナス値なら「時間です!」表示)に追いつきます。重要な終了通知が必要な場合は、PCはスリープせず画面の輝度を下げる程度に留めるのが推奨です。

6. 終了音をWebAudioで生成する理由

音声ファイル(mp3/wav)を再生する方式だと、ファイルダウンロード・iOS Safari の自動再生ポリシー・モバイルの省電力制約など複数のハードルがあります。手軽屋のタイマーは AudioContext で880Hz のオシレーター音を3回鳴らす方式で、ファイル不要・即時再生・全ブラウザ対応を実現しています。Web Audio APIは音を「数式から合成」できるため、タイマー終了音のような短いビープには最適です。

手軽屋ツール実践手順

  1. タイマー・ストップウォッチを開く
  2. 時間を設定してスタート
  3. 別タブに切り替えて作業しても残り時間は正確
  4. タブのタイトルにも残り時間が表示される
  5. PCのスリープを避ければ終了音が鳴る
  6. ストップウォッチも同じ仕組みで累積時間が狂わない

関連ツール

参照: Page Visibility API(MDN)