バックグラウンドタブかどうかに関わらず setTimeout()
や setInterval()
がとても不正確なのはそういう仕様なので、これらの正確さに依存した設計は避けるべきです。HTMLページ上では、「正確にある間隔でコードを実行する」というのはそもそも不可能だという前提を持つ必要があります。
たとえば、「200ms 毎に配列の現在のインデックスの要素を処理して、現在のインデックスに1を足す」のような処理は「処理開始からN ms 後のインデックスを計算する」という処理に変更しましょう。
BAD:
js
1let array = [..];
2// array[0] を処理
3let arrayIndex = 1;
4setInterval(() => {
5 // array[arrayIndex] を処理
6 arrayIndex++;
7}, 200);
GOOD:
js
1let array = [..];
2const startTime = performance.now();
3requestAnimationFrame(handleFrame);
4function handleFrame(timeStamp) {
5 const arrayIndex = Math.floor((timeStamp - startTime) / 200) % array.length;
6 // array[arrayIndex] を処理
7 requestAnimationFrame(handleFrame);
8}
「200ms毎にある関数を呼ぶ」のような処理は「処理開始からN ms 経過後なら合計 N / 200 回呼ぶ」という処理に変更しましょう。
BAD:
GOOD:
js
1const startTime = performance.now();
2let fCount = 0;
3requestAnimationFrame(handleFrame);
4function handleFrame(timeStamp) {
5 const expectedCount = Math.floor((timeStamp - startTime) / 200);
6 for (; fCount < expectedCount; ++fCount)
7 f();
8 requestAnimationFrame(handleFrame);
9}
どうしても定期的に処理を行いたいこともあるとは思います。たとえば定期的にサーバにアクセスしないとサーバ側でタイムアウトしてしまうとか。そういう場合は Worker
を使います。