Question

J'ai remarqué que si je règle le setTimeout pendant 1 minute à l'avenir, puis que je change l'heure de mon système à 5 minutes dans le passé, la fonction setTimeout se déclenchera dans 6 minutes.

J'ai fait cela parce que je voulais voir ce qui se passe lors d'un changement d'heure d'été sur l'horloge système.

Ma page Web JavaScript utilise une fonction setTimeout pour actualiser automatiquement la page toutes les 5 secondes, et si l'heure d'été devait se produire, les informations de la page se figeraient pendant une heure.Y a-t-il une solution de contournement?

Modifier: je mets à jour la page en utilisant Ajax, je ne veux pas actualiser la page entière.

Était-ce utile?

La solution

Ce que je vais faire, c'est changer l'ouverture d'une nouvelle requête Ajax toutes les 5 secondes pour utiliser Comet (sondage long).C'est une meilleure option car le serveur transmettra les nouveaux résultats au navigateur chaque fois qu'ils sont nécessaires, cela peut être toutes les 5 secondes côté serveur ou chaque fois que de nouvelles informations sont disponibles.

Encore mieux serait d'utiliser des sockets Web et d'avoir Comet comme solution de secours.Ceci est facile à mettre en œuvre avec Faye ou socket.oi .

Il existe d'autres options, comme CometD o Ape.

Autres conseils

Utilisez setInterval au lieu de setTimeout et vos problèmes devraient être résolus :)

Mise à jour:

Si vous ne pouvez vraiment pas utiliser setTimeout ou setInterval, vous pouvez essayer d'avoir un iframe caché qui charge une page HTML simple qui ressemble à ceci:

<html>
    <head>
        <meta http-equiv="refresh" content="300"/>
        <script>
            document.domain='same as parent page';
            top.ajax_function_you_wish_to_trigger();
        </script>
    </head>
    <body>
    </body>
</html>

Si vous avez de la chance, l'actualisation de la méta ne vous posera pas les mêmes problèmes.

Une autre solution serait de déplacer le déclenchement de l'événement sur le serveur via serveur push .Il y a de nombreuses raisons de ne pas le faire, notamment le fait que vous centraliseriez les événements et en feriez une charge sur le serveur, mais cela pourrait être considéré comme un dernier recours.

J'ai également rencontré ce problème récemment.Dans mon cas, le changement d'heure pouvait entraîner de graves pertes financières, je devais donc le prendre au sérieux.

Quelques informations générales:

  • IE et Opera gèrent correctement le changement d'heure des systèmes (aucun effet secondaire à setTimeout, setInterval).
  • FF <4.0 et tous les navigateurs basés sur Webkit ne parviennent pas à gérer le changement de temps vers le passé (exactement comme vous l'avez décrit).Remarque: les minuteries dans Chrome ne s'arrêtent toutefois qu'après un certain temps ~ 2-60 s.

Ma solution: utilisez un événement de l'interaction de l'utilisateur (par exemple, mousemove, mouseove, etc.) pour déclencher le contrôle du changement d'heure.

Clock.prototype.checkLocalTime = function(){
var diff = Date.now()- this.lastTimestamp;
if ( diff < 0 || diff > 20000) { // if time shifted back or more than 20s to the future
    console.warn('System time changed! By ' + diff + 'ms' );
    this.restartTimer();
    this.getServerTime();
}
this.lastTimestamp = time;

}

Comme vous pouvez le constater, je redémarre la minuterie et synchronise en plus l'heure avec le serveur.

Vous pouvez utiliser l'actualisation de la balise Meta pour ce faire.Ce code actualiserait la page toutes les 5 secondes:

<meta http-equiv="refresh" content="5"> 

Quant à la question javascript, il se peut que ce soit la manière dont le navigateur gère le setTimeout.Il indique au navigateur d'exécuter le code à une heure définie, puis lorsque l'horloge change, le code s'exécute toujours à l'heure avant que l'horloge ne change?Juste une supposition, mais je devrai garder cela à l'esprit la prochaine fois que j'utiliserai setTimeout.

Edit: Ok, cela ne fonctionnerait pas pour ajax Edit Again: C'est une très bonne question.Je suis sûr que setTimeout fonctionne comme je l'ai dit ci-dessus, mais wow, c'est un casse-tête.

Vous pouvez truquer et faire une vérification de if (Date in range foo).En gros, vérifiez si l'horodatage actuel est à moins de 5 secondes de l'heure d'été, puis actualisez la page immédiatement plutôt qu'en utilisant setTimeout.

De cette façon, les utilisateurs reçoivent un léger désagrément à l'approche d'un changement d'heure connu, mais la page ne se fige pas pendant une heure.

J'ai trouvé qu'en utilisant window.performance m'a donné des résultats plus précis et a maintenu les choses cohérentes lorsque l'heure du système change.

J'ai utilisé cela comme un moyen d'obtenir l'heure actuelle dans un tick setInterval afin qu'un compte à rebours ne soit pas affecté par un changement d'heure système.Je le calculais en fonction du nombre de ticks à un moment donné pour tenter d'éviter de tricher sur la minuterie (obtenir plus de temps) en changeant l'horloge système

getCurrentTime = () => {
  return window.performance ?
    performance.timing.navigationStart + performance.now() : Date.now();
}

tick() {
  let now = this.getCurrentTime();

  if (this.calibrateTime) { //calibrate with a given server time
    now -= this.timeCalibration;
  }

  const elapsedSeconds = (now - this.startedAt) / 1000;

  if (elapsedSeconds > this.props.timeLimit + this.props.submitBuffer) {
    clearInterval(this.interval);
    this.props.onTimeUp();
  }

  let secondsRemaining = this.props.timeLimit - Math.floor(elapsedSeconds);
  if (secondsRemaining < 0) secondsRemaining = 0;

}

startTimer() {
  if (!this.startedAt) {
    this.startedAt = Date.now();
  }

  this.setState({ started: true }, () => {
    this.interval = setInterval(this.tick.bind(this), 500);
  });
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top