web-dev-qa-db-fra.com

Appeler Settimeout sans délai

Très souvent, voir dans le code des bibliothèques JavaScript comme ceci:

setTimeout(function() {
    ...
}, 0);

J'aimerais savoir pourquoi utiliser un tel code d'emballage.

41
defuz

Très simplifié:

Les navigateurs sont à un seul filetage et ce fil unique (le fil de l'interface utilisateur) est partagé entre le moteur de rendu et le moteur JS.

Si la chose que vous voulez faire prend beaucoup de temps (nous parlons des cycles ici mais quand même) cela pourrait arrêter (paus) le rendu (flux et peinture).

Dans les navigateurs, il existe également "le seau" où tous les événements sont mis en place pour que le fil de l'interface utilisateur soit effectué avec tout ce qu'il en va. Dès que le fil est fait, il regarde dans le seau et choisit la tâche d'abord en ligne.

À l'aide de setTimeout Vous créez une nouvelle tâche dans le compartiment après le délai et laissez le thread le traiter dès qu'il est disponible pour plus de travail.

Une histoire:

Après 0 ms Delay, créez une nouvelle tâche de la fonction et mettez-la dans le godet. À ce moment précis, le fil de l'interface utilisateur est occupé à faire autre chose, et il y a déjà une autre tâche dans le seau déjà. Après 6 ms, le thread est disponible et obtient la tâche en face de la vôtre, bon, vous êtes la suivante. Mais quoi? C'était une grande chose! Il a été comme ForeEeeeeever (30ms) !!

Enfin, le fil est fait avec cela et vient et obtient votre tâche.

La plupart des navigateurs ont un délai minimum qui est plus que 0 alors mettant 0 comme retard moyen: mettre cette tâche dans le panier dès que possible. Mais dire à l'UA de le mettre dans le seau dès que possible n'est pas une garantie qu'il s'exécutera à ce moment-là. Le godet est comme le bureau de poste, il se pourrait qu'il existe une longue file d'attente d'autres tâches. Les bureaux de poste sont également filetés avec une seule personne qui aide toute la tâche ... Désolé les clients avec leurs tâches. Votre tâche doit entrer dans la ligne comme tout le monde.

Si le navigateur ne met pas en œuvre son propre ticker, il utilise les cycles de ticks du système d'exploitation. Les navigateurs plus âgés avaient des retards minimum entre 10-15ms. HTML5 Spécifie que si le délai est inférieur à 4 ms, l'UA devrait l'augmenter à 4 ms. Ceci est dit cohérent entre les navigateurs libérés en 2010 et en avant .

Voir Comment fonctionne les minuteurs JavaScript par John Resig pour plus de détails.

Edit: Voir aussi Qu'est-ce que Heck est la boucle d'événement quand même? Par Philip Roberts de JSCONF EU 2014. C'est la visualisation obligatoire Pour toutes les personnes touchant le code frontal.

64
anddoutoi

Il y a quelques raisons pour lesquelles vous feriez cela

  • Il y a une action que vous ne voulez pas courir immédiatement mais que vous voulez courir à une période proche future.
  • Vous souhaitez autoriser d'autres gestionnaires déjà enregistrés à partir d'un setTimeout ou setInterval à exécuter
10
JaredPar

Outre les réponses précédentes, j'aimerais ajouter un autre scénario utile que je peux penser: "s'échapper" d'un bloc d'essais. Un retard de sécurité de l'intérieur d'un bloc d'essais sera exécuté en dehors du bloc et toute exception se propagera à la place de la portée globale.

Peut-être que Meilleur exemple de scénario: dans le JavaScript actuel, avec l'utilisation plus courante des appels de différés/promesses pour les rappels asynchrones, vous êtes (souvent) en réalité dans une prise d'essai. Referreds/Promess envelopper le rappel dans une capture essaie de pouvoir détecter et propager une exception comme une erreur dans la chaîne ASYNC. Ceci est tout bon pour les fonctions qui doivent être dans la chaîne, mais tôt ou tard, vous êtes "fait" (c.-à-d. Agrandir tout votre Ajax) et vouloir exécuter un code de non-async nature où vous ne voulez pas que des exceptions soient " caché "plus. Afaik Dojo, Kris Kowal's Q, Mochikit et Google Fermeture Lib utilisent l'emballage de try-capture (pas jQuery toutefois).

(À quelques occasions étranges, j'ai également utilisé la technique pour redémarrer le code de style singleton sans causer de la récursivité. Je fais un démarrage-redémarrage de la même boucle).

7
Fredrik Blomqvist

Lorsque vous souhaitez exécuter le reste de votre code sans attendre le précédent terminé, vous devez l'ajouter dans la méthode anonyme transmise à la fonction de sécurité. Sinon, votre code attendra jusqu'à ce que le précédent soit fait

Exemple :

function callMe()
{
   for(var i = 0; i < 100000; i++)
     {
       document.title = i;
     }
} 

var x = 10;
setTimeout(callMe, 0);

var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';

C'est la raison pour laquelle je l'utilise.

4
Senad Meškin

Permettre aux délais d'attente précédemment définis à exécuter.

1
HBP