2025/09/03 05:13 Why do browsers throttle JavaScript timers?

やあ、ロボ子。今日はsetTimeoutの意外な落とし穴について話すのじゃ。

setTimeout、ですか?setTimeout(0)でほぼ即時実行されると思っていましたが…。

それが違うのじゃ!ブラウザはsetTimeoutの濫用を防ぐために、最小4msの「クランプ」を設定しておる。つまり、setTimeout(0)と書いても、実際には4ms後になる可能性があるのじゃ。

4msも遅延するんですか!それは結構大きな違いですね。特に、fake-indexeddbでIndexedDBトランザクションの自動コミットにsetTimeoutを使っている場合、Node.jsと比べてChromeで16倍も遅れることがあるんですね。

そう、ロボ子の言う通りじゃ。バッテリー駆動のデバイスやバックグラウンドタブでは、さらに積極的にスロットリングされることもあるからの。

では、setTimeoutの代わりに何を使うべきでしょうか?記事には、setImmediate、MessageChannel.postMessage、window.postMessage、scheduler.postTaskなどが挙げられていますね。

その通りじゃ!ベンチマークの結果を見ると、ChromeとFirefoxはsetTimeoutを4msにクランプするが、Safariではさらに強くスロットリングされるようじゃな。そして、scheduler.postTaskが最もパフォーマンスが高いのじゃ。

scheduler.postTaskですか。初めて聞きました。fake-indexeddbでは、scheduler.postTaskを使い、MessageChannel.postMessageまたはwindow.postMessageにフォールバックしているんですね。

ブラウザがsetTimeoutをスロットリングする理由は、Web開発者を保護するためじゃ。Web開発者がより良い選択肢を知らない場合があるからの。親切設計じゃな。

なるほど。postTaskとpostMessageは当面スロットリングされないと予測されているんですね。setIntervalについてもsetTimeoutと同様のことが言える、と。

setIntervalも要注意じゃぞ!そして、Safariでは、fake-indexeddbはMessageChannelやwindow.postMessageではなく、依然としてsetTimeoutにフォールバックしているというのも興味深い点じゃ。

setTimeoutの奥深さを知りました。これからはタイマーを使う際には、scheduler.postTaskを検討し、ブラウザごとの挙動の違いにも注意する必要がありそうですね。

その通りじゃ!しかし、setTimeoutが遅れるからといって、待ち合わせに遅刻するのはナシじゃぞ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。