Maison > interface Web > js tutoriel > Explication détaillée d'exemples de boucles d'événements js

Explication détaillée d'exemples de boucles d'événements js

零下一度
Libérer: 2017-06-26 09:17:38
original
1295 Les gens l'ont consulté

J'ai déjà lu quelques blogs sur les boucles d'événements, mais après ne pas les avoir lus pendant un moment, j'ai réalisé que je les avais tous oubliés, alors j'ai décidé d'écrire un blog pour les résumer !

Tout d'abord, expliquons ce qu'est la boucle d'événements :

Pour autant que nous le sachions, le js du navigateur est monothread, c'est-à-dire disons, au plus un seul segment de code s'exécute en même temps, mais le navigateur peut très bien gérer les requêtes asynchrones, alors pourquoi ? Regardons d'abord une image
Explication détaillée dexemples de boucles dévénements js
À partir de l'image ci-dessus, nous pouvons voir que le thread principal js a une pile d'exécution et que tout le code js s'exécutera dans la pile d'exécution. Lors de l'exécution du code, si vous rencontrez du code asynchrone (tel que setTimeout, ajax, promise.then et les clics de l'utilisateur, etc.), alors le navigateur mettra ces codes dans un thread (ici nous l'appelons un derrière-le -scenes thread) L'attente ne bloque pas l'exécution du thread principal. Le thread principal continue d'exécuter le code restant dans la pile lorsque le code du thread d'arrière-plan est prêt (par exemple, le délai setTimeout est écoulé et la requête ajax. reçoit une réponse), le thread le traitera. La fonction de rappel est placée dans la file d'attente des tâches en attente d'exécution. Lorsque le thread principal aura fini d'exécuter tout le code de la pile, il vérifiera s'il y a une tâche à exécuter dans la File d'attente des tâches S'il y a une tâche à exécuter, alors la tâche sera mise. dans la pile d'exécution pour l'exécution. Si la file d'attente des tâches actuelle est vide, elle continuera d'attendre en boucle que la tâche arrive. C’est ce qu’on appelle une boucle d’événements.

Alors, voici la question. S’il y a de nombreuses tâches dans la file d’attente des tâches, laquelle doit être exécutée en premier ?

En fait (comme le montre l'image ci-dessus), js a deux files d'attente de tâches, l'une s'appelle Macrotask Queue (Task Queue) et l'autre s'appelle Microtask Queue

  • Le premier est principalement utilisé pour effectuer des travaux à relativement grande échelle, les plus courants incluent setTimeout, setInterval, les opérations d'interaction utilisateur, le rendu de l'interface utilisateur, etc.

  • Le second est principalement utilisé pour effectuer des travaux à relativement petite échelle, ce qui est courant. Il existe Promise, process.nextTick (nodejs)

Alors, quelles sont les différences spécifiques entre les deux ? , si deux tâches apparaissent en même temps, laquelle faut-il choisir ?
En fait, ce que fait la boucle d'événements est la suivante :

  1. Vérifier si la file d'attente des macrotâches est vide . Sinon, passez à l'étape suivante. Si elle est vide, passez à 3

  2. Prendre la tâche en tête de file d'attente (avec le temps d'attente le plus long) depuis la liste. File d'attente Macrotask et exécutez-la dans la pile d'exécution (une seule). Après l'exécution, passez à l'étape suivante

  3. Vérifiez si la file d'attente Microtask est vide, sinon passez à l'étape suivante. , sinon, passez à 1 (démarrez une nouvelle boucle d'événements)

  4. Obtenir de la file d'attente Microtask La tâche en tête de file d'attente (avec le temps le plus long dans la file d'attente) va dans la file d'attente des événements pour l'exécution. Après l'exécution, passe à 3

Parmi eux, la tâche de microtâche ajoutée lors de l'exécution du code sera dans la période actuelle de la boucle d'événement. , et la tâche de macrotâche nouvellement ajoutée ne peut attendre que la prochaine boucle d'événement pour s'exécuter (une boucle d'événement n'exécute qu'une seule macrotâche)
Tout d'abord, regardons un morceau de code

console.log(1)
setTimeout(function() {
  //settimeout1
  console.log(2)
}, 0);
const intervalId = setInterval(function() {
  //setinterval1
  console.log(3)
}, 0)
setTimeout(function() {
  //settimeout2
  console.log(10)
  new Promise(function(resolve) {
    //promise1
    console.log(11)
    resolve()
  })
  .then(function() {
    console.log(12)
  })
  .then(function() {
    console.log(13)
    clearInterval(intervalId)
  })
}, 0);

//promise2
Promise.resolve()
  .then(function() {
    console.log(7)
  })
  .then(function() {
    console.log(8)
  })
console.log(9)
Copier après la connexion

Que voulez-vous pensez-vous que le résultat devrait être ?
Les résultats que je génère dans l'environnement de nœud et la console Chrome sont les suivants :

1
9
7
8
2
3
10
11
12
13
Copier après la connexion

Dans l'exemple ci-dessus
la première boucle d'événement :

  1. console.log(1) est exécuté, sortie 1

  2. settimeout1 est exécuté et ajouté à la file d'attente des macrotâches

  3. setinterval1 est exécuté et ajouté à la file d'attente des macrotâches

  4. settimeout2 est exécuté et ajouté à la file d'attente des macrotâches

  5. promise2 est exécuté et ses deux La fonction then est ajoutée à la file d'attente des microtâches

  6. console.log(9) est exécutée et la sortie est 9

  7. Selon la définition de la boucle d'événements, new sera exécuté ensuite. Les tâches de microtâches ajoutées sont exécutées dans l'ordre d'entrée dans la file d'attente. Console.log(7) et console.log(8) sont affichés. sont affichés. La file d'attente des microtâches est vide. Revenez à la première étape et entrez dans la boucle d'événements suivante. À ce stade, la file d'attente des macrotâches est : settimeout1, setinterval1, settimeout2

La deuxième boucle d'événements :

    de la file d'attente des macrotâches Obtenez la tâche en tête de l'équipe (settimeout1) et exécutez-la Sortie 2
  1. La file d'attente des microtâches est. vide. Revenez à la première étape et entrez dans la boucle d'événements suivante. À ce stade, la file d'attente des macrotâches est : setinterval1, settimeout2


La troisième boucle d'événements :

.

    Prenez la tâche à la tête de l'équipe (setinterval1) de la file d'attente des macrotâches et exécutez-la, sortie 3, puis ajoutez le setinterval1 nouvellement généré à la file d'attente des macrotâches
  1. Le La file d'attente des microtâches est vide, revenez à la première étape et entrez dans la boucle d'événements suivante. À ce moment, la file d'attente des macrotâches est : settimeout2, setinterval1


La quatrième boucle d'événements :

    Prenez la tâche à la tête de l'équipe (settimeout2) de la file d'attente des macrotâches et exécutez-la, sortie 10, et exécutez la fonction dans la nouvelle promesse (la fonction dans la nouvelle promesse est une opération synchrone, pas une opération asynchrone), sortie 11, et ajoute ses deux fonctions then à la file d'attente des microtâches
  1. Depuis la file d'attente des microtâches, prenez la tâche en tête de file d'attente et exécutez-la jusqu'à ce qu'elle soit vide. Par conséquent, les deux tâches de microtâches nouvellement ajoutées sont exécutées en séquence, sorties 12 et 13, et setinterval1 est effacé
    À ce moment, la file d'attente des microtâches et la file d'attente des macrotâches sont vides, et le navigateur vérifiera toujours si la file d'attente est vide et attends le nouveau. La tâche est ajoutée à la file d'attente.

Ici, vous vous demandez peut-être, dans la première boucle, pourquoi la macrotâche n'est-elle pas exécutée en premier ? Car selon le processus, ne devrions-nous pas d'abord vérifier si la file d'attente des macrotâches est vide, puis vérifier la file d'attente des microtâches ?
Raison : Parce que la tâche exécutée dans le thread principal js au début est la tâche de macrotâche, et selon le processus de la boucle d'événement, une seule tâche de macrotâche sera exécutée dans une boucle d'événement. Par conséquent, après l'exécution du code. du thread principal, il ira de Prenez la première tâche de la file d'attente des microtâches et exécutez-la.

Remarque :

Lors de l'exécution d'une tâche de microtâche, elle n'entrera dans la boucle d'événements suivante que lorsque la file d'attente des microtâches est vide. Par conséquent, si elle génère continuellement de nouvelles. Les tâches de microtâches entraîneront l'exécution de tâches de microtâches par le thread principal, et il n'y a aucun moyen d'exécuter des tâches de macrotâches. De cette façon, nous ne pourrons pas effectuer de rendu d'interface utilisateur/opérations d'E/S/requêtes ajax. Par conséquent, nous devrions éviter cette situation. . se produire. Dans process.nexttick dans nodejs, vous pouvez définir le nombre maximum d'appels pour éviter de bloquer le thread principal.

Avec cela, nous introduisons un nouveau problème, le problème de la minuterie. La minuterie est-elle réelle et fiable ? Par exemple, si j'exécute une commande : setTimeout(task, 100), sera-t-elle exécutée exactement après 100 millisecondes ? En fait, sur la base de la discussion ci-dessus, nous pouvons savoir que cela est impossible.
Je pense que tout le monde devrait connaître la raison, car après avoir exécuté setTimeout(task,100), vous vous assurez simplement que la tâche entrera dans la file d'attente des macrotâches après 100 millisecondes, mais cela ne signifie pas qu'elle peut s'exécuter immédiatement, peut-être Le thread principal effectue actuellement une opération fastidieuse, ou il peut y avoir de nombreuses tâches dans la file d'attente des microtâches, c'est peut-être la raison pour laquelle tout le monde a critiqué setTimeout

Ce qui précède n'est que mon point de vue personnel. de la boucle événementielle. Quelques avis et références d'autres excellents articles

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal