最近、実生活でフットガンを発見しました。これは setTimeout に関連していました。セール タイマーのために、たとえば 28 日間タイムアウトを実行する必要があり、終了の UTC タイムスタンプがありました。ということで、素朴なアプローチでこれを実行しました
const date1 = new Date(timestamp1); // Difference in milliseconds const timeout = date2.getTime() - Date.now(); setTimeout(()=>{ // some code to turn off some flags / remove some banner },timeout);
驚いたことに、これは機能しなかったか、あまりにもうまく機能しすぎました。setTimeout 内のコードがタイムアウトを待たずに実行されたため、ブラウザでデバッグすることにしました。すると、コントロールがほぼ即座に setTimeout コールバックにジャンプすることがわかりました。
setTimeout の MDN ページ (https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value ) を見ると、 setTimeout() が実行されるまでの最大制限があることが明らかでした。正確に、具体的に
2,147,483,647 ミリ秒、または (24.8 日)、または (2**31 - 1) ミリ秒。これは、ブラウザーが内部的に遅延を 32 ビットの符号付き整数として保存するためです。
したがって、24.8 日を超えるタイムアウトを渡すと常に整数オーバーフローが発生し、コードはすぐに実行されるか、予想よりも短いタイムアウト期間で実行されます。それは残念ですが、間違いはありません !!!
const days = 30; const timeout = days * 24 * 60 * 60 * 1000; console.log('timeto', timeout); setTimeout(function () { console.log('ticked immediately'); // --> executed almost instantly }, timeout); class LongTimeout { constructor(cb, timeout) { this.timeStart = document.timeline ? document.timeline.currentTime : performance.now(); this.lastAnimationFrame = this.runTimer(cb, timeout); } runTimer(cb, timeout) { if(this.cancelled) return; const currTimeStamp = performance.now(); const elapsed = currTimeStamp - this.timeStart; if (elapsed >= timeout) { cb(); window.cancelAnimationFrame(this.lastAnimationFrame); } else { console.log('tick', elapsed, timeout); this.lastAnimationFrame = requestAnimationFrame(() => this.runTimer(cb, timeout) ); } } cancelTimeout() { window.cancelAnimationFrame(this.lastAnimationFrame); this.cancelled = true; this.lastAnimationFrame = null; } } const longTimer = new LongTimeout(() => { console.log(`Tick after ${timeout}`); // timeout works -> does not execute immediately }, timeout);
以上がsetTimeout - 最大タイムアウト フットガンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。