Maison  >  Article  >  interface Web  >  setTimeout - pistolet à pied avec délai d'attente maximum

setTimeout - pistolet à pied avec délai d'attente maximum

Linda Hamilton
Linda Hamiltonoriginal
2024-11-23 16:48:21747parcourir

setTimeout - max timeout footgun

Récemment, j'ai découvert un pistolet à pied dans la vraie vie, qui était lié à setTimeout, j'ai dû exécuter un délai d'attente pendant, disons, 28 jours pour un minuteur de vente, j'avais un horodatage UTC pour la fin jour, donc avec une approche naïve, j'ai fait ça

 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);

À ma grande surprise, cela n'a pas fonctionné ou a trop bien fonctionné, puisque le code de setTimeout s'est exécuté sans attendre le délai d'attente, j'ai décidé de déboguer dans le navigateur et j'ai vu que le contrôle sautait presque instantanément dans le rappel setTimeout.

Quel est le problème ici ?

En regardant la page MDN de setTimeout, https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value , il était clair qu'il y avait une limite maximale jusqu'à laquelle setTimeout() s'exécuterait avec précision, spécifiquement
2 147 483 647 ms ou (24,8 jours) ou (2**31 - 1) ms, cela est dû au fait que les navigateurs stockent le délai sous la forme d'un entier signé de 32 bits en interne.

Ainsi, à chaque fois que vous dépassez un timeout de plus de 24,8 jours, il y a un débordement d'entier et le code est exécuté immédiatement ou plutôt avec une durée de timeout inférieure à celle prévue. C'est dommage, et il n'y a pas d'erreur !!!

Solutions possibles à ce problème

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);

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn