Maison > Article > interface Web > Introduction détaillée à setTimeout dans la fonction JS
Cet article présente principalement le processus d'exécution de la fonction js de setTimeout. Les amis qui en ont besoin peuvent s'y référer
Pour être honnête, lorsque j'ai écrit cet article, je me suis senti un peu déprimé parce que j'étais choqué. Pourquoi ? Juste parce que j'aime déconner, j'ai vu par hasard cette fonction "simple" :
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, i * 1000); } console.log(i);
Quoi ? N'est-ce pas la méthode de mise en œuvre que j'ai vue il y a longtemps consistant à imprimer un 5, puis un 5, puis à imprimer un 5 toutes les secondes jusqu'à ce que 6 5 soient imprimés ? Alors voici la question, que dois-je faire si je veux imprimer 0, 1, 2, 3, 4, 5 en séquence ? En fait, je savais qu'il y avait ces deux méthodes avant : l'une est comme ceci :
function log(i){ setTimeout(function(){ console.log(i) },i*1000) }; for (var i = 0; i < 5; i++) { log(i) ; } console.log(i);
Une autre est comme ceci :
for(var i=0;i<5;i++){ (function(e){ setTimeout(function(){ console.log(e) },i*1000); })(i); }; console.log(i);
Je n'ai pas peur des blagues. Je ne comprenais pas à quoi servaient réellement ces deux fonctions avant cela, alors je me suis juste forcé à le faire. souvenez-vous-en comme ça. C'est bien de le modifier comme ça, mais ça ne marche pas maintenant, j'ai un trouble obsessionnel-compulsif ! Donc, je l'ai lentement analysé et j'ai découvert que le code ci-dessus peut être séparé en ceci : lorsque
i=0;
setTimeout(function(){ console.log(i) },0*1000);
i=1; est rempli ;
setTimeout(function(){ console.log(i) },1*1000);
Quand i=2; la condition est remplie
setTimeout(function(){ console.log(i) },2*1000);
i=3; =4; la condition est remplie ;
setTimeout(function(){ console.log(i) },3*1000);
Lorsque i=5, la condition n'est pas remplie, sortez de la boucle, puis exécutez console.log(i) après la boucle for, en imprimant 5 ; enfin, imprimez-en 5 toutes les secondes
setTimeout(function(){ console.log(i) },4*1000);C'est vraiment intéressant, pourquoi le console.log à l'intérieur de setTimeout est-il exécuté après le console.log en dehors de la boucle for ? Jusqu'à ce que je réalise le mot => "file d'attente", les files d'attente sont divisées en file d'attente de tâches macro (Macro Task) et en file d'attente de micro tâches (Micro Task). En javascript : la macro-tâche comprend : script (Code global). , setTimeout, setInterval, setImmediate, I/O, rendu de l'interface utilisateur. la micro-tâche comprend : process.nextTick, Promises, Object.observe, MutationObserverLe setTimeout de la fonction ci-dessus appartient à la tâche macro En js, l'ordre de la boucle d'événement La première boucle démarre à partir du script, puis le contexte global entre dans la pile d'appel de fonction Lorsqu'une macro-tâche est rencontrée, elle est transmise au module qui la gère. Après traitement, la fonction de rappel est mise en place. la file d'attente de la macro-tâche Lorsqu'une micro-tâche est rencontrée, -task place également sa fonction de rappel dans la file d'attente des micro-tâches. Jusqu'à ce que la pile d'appels de fonction soit effacée et qu'il ne reste que le contexte d'exécution global, toutes les micro-tâches commencent à être exécutées. Une fois que toutes les micro-tâches exécutables ont été exécutées. La boucle exécute à nouveau une file d'attente de tâches dans la macro-tâche, puis exécute toutes les micro-tâches après l'exécution, et la boucle continue. C'est pourquoi le console.log à l'intérieur de setTimeout sera exécuté après le console.log en dehors de la boucle for. Dans le contexte d'exécution de la fonction, la fonction seiTimeout sera placée dans la file d'attente pour traiter sa macro-tâche. , donc la fonction dans setTimeout ne sera pas exécutée pendant la boucle, mais attendra que tout le code global (hors file d'attente) soit terminé avant que la fonction dans la file d'attente ne soit exécutée en écrivant ceci, je suis peut-être un peu confus, dans en fait, moi aussi Un peu confus, hahaha ! ! Afin d'approfondir votre compréhension, vous pouvez également essayer d'y ajouter Promise, alors voici ceci :
Expliquez-le=>
(function copy() { setTimeout(function() {console.log(4)}, 0); new Promise(function executor(resolve) { console.log(1); for( var i=0 ; i<10000 ; i++ ) { i == 9999 && resolve(); } console.log(2); }).then(function() { console.log(5); }); console.log(3); })()1. , script La source de la tâche est exécutée en premier et le contexte global est poussé sur la pile. 2. Lorsque le code source de la tâche de script rencontre setTimeout lors de l'exécution, en tant que macro-tâche, il place sa fonction de rappel dans sa propre file d'attente. 3. Le code de la source de la tâche de script rencontre une instance Promise lors de l'exécution. Le premier paramètre du constructeur Promise est que la tâche en cours ne sera pas mise dans la file d'attente si elle est exécutée directement, donc 1 est affiché à ce moment-là. 4. Lorsque vous rencontrez la fonction de résolution dans la boucle for, la fonction est poussée dans la pile puis ressorte. À ce moment, le statut de Promesse devient Réalisé. Le code s'exécute ensuite et rencontre console.log(2), qui génère 2. 5. Ensuite, exécutez, le code rencontre la méthode then, et sa fonction de rappel est poussée sur la pile en tant que micro-tâche et entre dans la file d'attente des tâches de Promise. À ce moment, la fonction de rappel de fonction est alors. de Promise et la fonction dans setTimeout Les fonctions de rappel ont la même signification et seront placées dans leurs files d'attente de tâches respectives Elles ne seront exécutées qu'après le contexte de la fonction, c'est-à-dire tout le code hors file d'attente dans le. script, a été exécuté. De plus, la file d'attente des microtâches est prioritaire sur la file d'attente des macrotâches Traitement, La séquence globale est : code de contexte hors file d'attente > code de fonction de rappel de la file d'attente des microtâches > code de la fonction de rappel de la file d'attente des macrotâches
6. Le code continue de s'exécuter et la console est rencontrée à ce moment-là, log(3), sortie 3.
7. Après la sortie de 3, le code du premier script de macrotâche est exécuté. À ce moment, toutes les micro-tâches de la file d'attente commencent à être exécutées. La fonction de rappel then est poussée sur la pile puis extraite. À ce moment, 5
8 est affiché. À ce moment, toutes les micro-tâches sont terminées et le premier tour de la boucle se termine. Le deuxième tour de boucle commence à partir de la file d'attente des tâches de setTimeout. La fonction de rappel de setTimeout est poussée dans la pile puis ressorte. À ce moment, 4 est affiché.
Enfin, afin d'approfondir votre compréhension, voici un autre morceau de code :
Si le résultat de votre exécution est : golb1=>glob1_promise=>glob1_then=>timeout1 =>timeout1_promise =>timeout1_then=>prp_timeout=>time_timeout=>timeout1_timeout1,Peut-être que la file d'attente asynchrone est une introduction ! ~~Le code ci-dessus semble un peu compliqué. Il est peut-être préférable d'utiliser des asyns et d'attendre pour le transformer, mais c'est plus ou moins l'idée que j'ai obtenue de setTimeout
Ce qui précède est ce que j'ai compilé pour tout le monde. J'espère que cela sera utile à tout le monde à l'avenir.
Articles connexes :
Comment implémenter le WeChat Jump Game à l'aide de Three.js
Introduction détaillée à l'implémentation http dans NODEJS
Comment implémenter la fonction de chat à l'aide de nodejs
Comment utiliser les fonctions avancées en JavaScript
Utilisation d'Angular5 Réaliser la pratique du rendu côté serveur
Comment réinitialiser l'état d'inactivité dans vuex
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!