web-dev-qa-db-fra.com

Que fait setTimeout lorsqu'il est réglé sur 0 millisecondes?

En JavaScript, setTimeout(callback, delay) signifie "appeler callback après delay millisecondes". Mais que faire si delay est 0? Doit-il appeler immédiatement callback?

Je suis confus à cause de ce que je vois lorsque j'exécute le code suivant:

setTimeout(function() { 
    console.log('AAA');
}, 0); // Call this in 0 milliseconds 

for (i = 0; i < 1000; i++) {
    console.log('BBB'); 
}
for (i = 0; i < 1000; i++) {
    console.log('CCC'); 
}
for (i = 0; i < 1000; i++) {
    console.log('DDD'); 
}
for (i = 0; i < 1000; i++) {
    console.log('EEE'); 
}

Cela enregistre les éléments suivants dans la console:

console_log

Je m'attendais à voir AAA connecté beaucoup plus tôt que cela. Il était temps d'exécuter 4000 autres appels à console.log devant une fonction qui aurait dû être appelée immédiatement.

Quelqu'un peut-il expliquer ce que setTimeout fait lorsque le délai est défini sur 0 millisecondes?

39
DDan

Quelques faits utiles pourraient aider à clarifier ce qui se passe:

  1. JavaScript est monothread. Les rappels asynchrones sont affectés à un message placé dans une file d'attente de messages.
  2. Lorsqu'aucun code n'est en cours d'exécution, la boucle - événement interroge la file d'attente de messages, demandant que le prochain message en ligne soit traité (exécuté).
  3. setTimeout ajoute un message (avec le rappel fourni) à la fin de cette file d'attente une fois le délai spécifié écoulé.

(Remarque: cela signifie que le retard dans un appel setTimeout n'est pas une chose sûre; c'est le délai minimum avant l'exécution du rappel . Le temps réel nécessaire dépend du temps qu'il faut pour traiter les messages qui le précèdent dans la file d'attente.)

Que se passe-t-il si le délai est défini sur 0? Un nouveau message est immédiatement ajouté à la file d'attente et sera traité lorsque le code en cours d'exécution sera terminé et que tous les messages ajoutés précédemment auront été traités.

Que se passe-t-il dans votre code

Lorsque vous appelez setTimeout

setTimeout(function() { 
    console.log('AAA');
}, 0);

… Un message est ajouté à la file d'attente avec le rappel spécifié. Le reste de votre code…

for (i = 0; i < 1000; i++) {
    console.log('BBB'); 
}
// etc.

… Continue de s'exécuter de manière synchrone. Une fois complètement terminée, la boucle d'événements interroge la file d'attente de messages pour le message suivant et trouve celle avec votre rappel setTimeout, qui est ensuite traitée (le rappel est exécuté).

Le rappel n'est exécuté que - après le code en cours d'exécution est terminé, peu importe le temps que cela prend.

Lectures complémentaires

Pour plus de détails sur la boucle d'événements, voir:

59
Jordan Gray