ホームページ  >  記事  >  ウェブフロントエンド  >  setTimeout - 最大タイムアウト フットガン

setTimeout - 最大タイムアウト フットガン

Linda Hamilton
Linda Hamiltonオリジナル
2024-11-23 16:48:21749ブラウズ

setTimeout - max timeout footgun

最近、実生活でフットガンを発見しました。これは 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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。