- JavaScriptで
setTimeout(0) は実際には即時実行されず、最小 4ms の遅延が入ることが多いが、これは乱用防止のためのブラウザの基本的な制限である
- こうした制約は、Webサイトがタイマーを無秩序に乱用して バッテリー消費 や インタラクション低下 を引き起こすのを防ぐための措置であり、バッテリーモードでは 16ms、バックグラウンドタブでは 1 秒へとさらに厳しく制限されることもある
- 開発者は
setTimeout の限界を回避するため、setImmediate、MessageChannel.postMessage、window.postMessage、scheduler.postTask など、さまざまな 代替タイマー API を活用してきた
- 実際のベンチマークでは、Chrome と Firefox では 4ms クランプが適用される一方、
MessageChannel と scheduler.postTask はほぼ遅延なく動作し、Safari は setTimeout をより強く制限する特徴を示した
- 根本的には、ユーザー体験の保護と開発者の自由のあいだのバランスの問題であり、現在は Scheduler API が標準化された解決策として定着しつつあるが、乱用が発生すれば新たな ブラウザ介入 (Intervention) が導入される可能性もある
setTimeout 制限の背景
別のタイマー API の登場
setImmediate: IE と旧 Edge でのみサポートされ、事実上廃止
MessageChannel.postMessage: 別チャネルを通じてイベントループに処理を渡す
window.postMessage: 性能は良いが、他のスクリプトと衝突するリスクがある
scheduler.postTask: 最新ブラウザでサポートされ、最も安定した選択肢として評価されている
ベンチマーク結果 (MacBook Pro 2021, 101回反復測定)
- Chrome 139:
setTimeout 4.2ms, scheduler.postTask 0ms
- Firefox 142:
setTimeout 4.72ms, scheduler.postTask 0.01ms
- Safari 18.4:
setTimeout 26.73ms, MessageChannel 0.52ms, window.postMessage 0.05ms
fake-indexeddb の事例
- IndexedDB は、イベントループのマイクロタスク終了直後にトランザクションの自動コミットを必要とする
- Node.js の
setImmediate は理想的だが、ブラウザでは setTimeout が非効率的である
- Chrome では 300ms で終わる作業が、ブラウザでは 4.8 秒まで伸びる問題が発生
- 解決策として
scheduler.postTask をデフォルトで使い、互換性のため MessageChannel / window.postMessage をフォールバックとして採用した
ブラウザ介入をめぐる議論
- 一方は、タイマーを制限すべきであり、それによって開発者が自分自身から守られると主張する
- 他方は、開発者が自ら測定・最適化できるよう 自由を保証 すべきだと主張する
- 結局、ユーザー優先の原則に従い、ブラウザは乱用防止のために介入 (intervention) する
- Scheduler API は両者の立場を折衷し、開発者に細かな タスク制御権 を与えつつ、ブラウザのレンダリングパイプラインと整合するよう設計されている
今後の見通し
postTask と postMessage は当面スロットリングなしで維持される見込み
- ただし、
user-blocking のような高優先度を乱用すれば、再び介入される可能性がある
- 長期的には、別の
scheduler2 のような代替 API が再び必要になるかもしれない
まだコメントはありません。