ChromeブラウザなどのJavaScriptでは、settimeout()は対象のウィンドウがアクティブ/フォーカスされている状態でないと動作が不安定になることがあります。
これはChromeなどの多くのブラウザがウィンドウがアクティブでない時にCPUの最適化の一つとして自動で動作する挙動です。
javascript - window.setTimeout behaviour when window not in focus - Stack Overflow modern browsers (especially on mobile devices) suspend execution of scripts in tabs that are out of focus to save CPU cycles
以下のスタックオーバーフローのページを参考にすると、多くの投稿が以下のようなsettimeoutを利用したsleep関数の実装をしています。
const sleep = m => new Promise(r => setTimeout(r, m));
これは以下のようにDate()を利用して相対的な待機でなく絶対的な待機とすることができます。
const sleep2 = (seconds) => {
const waitUntil = new Date().getTime() + seconds * 1000
while(new Date().getTime() < waitUntil) {
// do nothing
}
}
しかし、上記のwhile()を利用した方法は実行を停止/ハングさせてしまうため、settimeout()の方法とはまた違った問題/エラーに遭遇することになる場合があります。
その場合、以下の方法がよりオールラウンドに活用できます。 最適化面、CPUには少し優しくありませんが、より確実に実行してくれます。
const sleep = m => new Promise(r => setTimeout(r, m));
const sleep2 = (mseconds) => new Promise(async r => {
const waitUntil = new Date().getTime() + mseconds
for (let i = 0; i < Infinity; i++) {
if (new Date().getTime() < waitUntil) {
await sleep(100);
} else {
break;
}
}
r();
});
これを以下のように利用します。
(async () => {
console.log("y")
await sleep2(1000) // 1秒待機
console.log("yy")
})();
あ
記事は間違いでした。以下訂正。
chromeのtimeoutがcpu最適化のためウィンドウがアクティブでない状態のときスロットリングされてしまうことが問題。
解決として、chromeのflag設定
chrome://flags/
からCalculate window occlusion on Windows
をdefault
からdisabled
に変更します。参考: FYI: how to disable timer throttling on Google Chrome : incremental_games