Cet article a aidé à résoudre un mal de tête majeur dans une application sur laquelle j'ai travaillé, donc un grand merci pour l'avoir posté. L'utilitaire AdjustTickCount est un outil fantastique et essentiel pour prouver des solutions, donc un coup de pouce pour cela aussi bien.
Le problème affecte également IE 7 et il semble également influer sur IE 6, mais avec des conséquences pires que le navigateur cesse de répondre tous ensemble et les solutions ne semblent pas travailler sur cette version soit. Il y a encore beaucoup d'utilisateurs de ces anciennes versions particulièrement dans le monde des affaires/entreprises.
Je n'ai pas trouvé que le bouton gauche de la souris était un facteur dans Windows XP, le problème se produit sans elle.
Les deux premières réponses sont correctes si le délai d'attente est de quelques secondes tout au plus et que seul un très petit nombre de délais d'attente est défini dans l'application. Si des délais d'attente plus longs et plus longs sont requis, il reste beaucoup à faire pour éviter que l'application Web devienne inutilisable. Dans un Web 2.0 RIA en utilisant un cadre tel que qooxdoo les utilisateurs peuvent le laisser fonctionner pendant des jours de sorte qu'il peut y avoir un plus grand besoin de délais plus longs et plus longs qu'un couple de demi-secondes pour produire une animation ou un autre bref effet. La première solution est un bon début mais régler le prochain délai à target-now
provoquera à nouveau l'appel de la fonction immédiatement car cela fera encore plus de temps de disponibilité + délai dépassera 2^32 millisecondes et donc le code JS tournera jusqu'à la disponibilité enveloppe autour de 0 (ou l'utilisateur tue le navigateur).
La deuxième solution est une amélioration parce que les délais d'attente prématurés ne se produiront à 1 seconde d'intervalle jusqu'à ce que maintenant est à moins de 1 seconde de l'enveloppe de disponibilité autour qui permet un autre code pour obtenir un look en mais des expériences ont montré que peut encore suffira à rendre le navigateur inutilisable s'il y a suffisamment de délais d'attente en attente. Et il continuera encore jusqu'à ce que le temps de disponibilité se termine donc si le délai demandé est assez long, l'utilisateur peut décider de tuer le navigateur.
Une solution moins gourmande en CPU est de définir le délai pour chaque temporisation suivante à la moitié de la temporisation précédente jusqu'à ce que ce délai soit inférieur à 500 ms, moment auquel nous savons que le temps de disponibilité est imminent (< 1 seconde) et nous pouvons définir le délai d'attente suivant à target-now
afin que la vérification du délai d'expiration prématurée cesse après seulement un petit nombre de cycles supplémentaires. Le temps nécessaire pour y parvenir dépendra de la durée du délai original et de la proximité du temps de fonctionnement lorsque setSafeTimeout
a été appelé, mais avec un minimum de chargement du processeur, l'application retrouve un comportement normal sans ralentissement prolongé pour l'utilisateur.
Quelque chose comme ceci:
function setSafeTimeout(func, delay) {
var target = +new Date + delay;
var newDelay = delay;
var helper = function()
{
var now = +new Date;
if (now < target)
{
newDelay /= 2; // halve the wait time and try again
if(newDelay < 500) // uptime wrap around is imminent
{
newDelay = target-now; // go back to using original target
}
var handle = setTimeout(helper, newDelay);
// if required record handle somewhere for clearTimeout
}
else
{
func();
}
};
return setTimeout(helper, delay);
};
raffinement supplémentaire:
J'ai trouvé que setTimeout()
peut parfois invoquer le rappel de quelques millisecondes plus tôt que prévu, même lorsque le temps de fonctionnement du système tiques ne sont pas près de 2^32 ms. Dans ce cas, l'intervalle d'attente suivant utilisé dans la fonction ci-dessus peut être supérieur au temps restant à la cible d'origine, ce qui entraîne une attente plus longue que celle initialement souhaitée.
Ci-dessous est une autre version qui résout ce problème:
function setSafeTimeout(func, delay) {
var target = +new Date + delay;
var newDelay = delay;
var helper = function()
{
var now = +new Date;
if (now < target)
{
var timeToTarget = target-now;
newDelay /= 2; // halve the wait time and try again
if(newDelay < 500 || newDelay > timeToTarget) // uptime wrap around is imminent
{
newDelay = timeToTarget; // go back to using original target
}
var handle = setTimeout(helper, newDelay);
// if required record handle somewhere for clearTimeout
}
else
{
func();
}
};
return setTimeout(helper, delay);
};
Y at-il une question? Cherchez-vous une solution de contournement ou partagez-la avec le monde? –
Sooo ... vous êtes en train de dire que faire un timeout pendant 24h après 25 jours de disponibilité du système sera un bug? Je me demande quand j'ai besoin d'un tel délai? –
Ceci est plus documentant un bug dans IE8. Pour un exemple de situation où cela pourrait poser un problème, disons que vous avez un feu de minuteur au bout d'une heure et que vous redirigez un utilisateur vers une autre page lorsqu'il se déclenche. Lorsque vous êtes dans une heure de 2^32 millisecondes de disponibilité, la minuterie se déclenchera immédiatement et l'utilisateur ne pourra pas accéder à la page d'origine. Une fois que le temps de fonctionnement passe 2^32 millisecondes, tout recommence à fonctionner. Mais pour cette heure, la page sera brisée. – user281806