Maison  >  Article  >  interface Web  >  Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

青灯夜游
青灯夜游avant
2022-01-05 10:29:572569parcourir

Cet article vous permettra d'explorer pourquoi le navigateur et Node.js conçoivent EventLoop comme celui-ci. J'espère que cela sera utile à tout le monde !

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Event Loop est un concept de base de JavaScript. C'est une question incontournable dans les entretiens et on en parle souvent dans la vie quotidienne. Mais avez-vous déjà réfléchi à la raison pour laquelle Event Loop existe et pourquoi il est conçu comme ça ?

Aujourd'hui, nous allons explorer les raisons.

La boucle d'événements du navigateur

JavaScript est utilisé pour implémenter une logique d'interaction de page Web, impliquant des opérations dom si plusieurs threads fonctionnent en même temps, la synchronisation et l'exclusion mutuelle sont nécessaires pour plus de simplicité, il est conçu pour être unique. threadé, mais s'il est monothread, il sera bloqué lorsqu'il rencontrera une logique de synchronisation et des requêtes réseau. Ce qu'il faut faire?

Vous pouvez ajouter une couche de logique de planification. Encapsulez simplement le code JS dans des tâches et placez-les dans une file d'attente de tâches, et le thread principal continuera à récupérer les tâches et à les exécuter.

Chaque fois qu'une tâche est récupérée et exécutée, une nouvelle pile d'appels sera créée.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Parmi eux, les minuteries et les requêtes réseau sont en fait exécutées dans d'autres threads. Après l'exécution, une tâche est placée dans la file d'attente des tâches pour indiquer au thread principal de continuer l'exécution.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Étant donné que ces tâches asynchrones sont exécutées dans d'autres threads, puis notifiées au thread principal via la file d'attente des tâches, il s'agit d'un mécanisme d'événement, cette boucle est donc appelée Event Loop.

Ces tâches asynchrones exécutées dans d'autres threads incluent des minuteries (setTimeout, setInterval), le rendu de l'interface utilisateur et les requêtes réseau (XHR ou fetch).

Cependant, il y a un sérieux problème avec la boucle d'événement actuelle. Il n'y a pas de notion de priorité et elle est uniquement exécutée dans l'ordre. S'il y a des tâches hautement prioritaires, elles ne seront pas exécutées à temps. Par conséquent, un mécanisme permettant de contourner les files d’attente doit être conçu.

Ensuite, créez simplement une file d'attente de tâches hautement prioritaires. Après l'exécution de chaque tâche ordinaire, toutes les tâches hautement prioritaires sont exécutées, puis les tâches ordinaires sont exécutées.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Grâce au mécanisme de saut de file d'attente, des tâches de haute qualité peuvent être exécutées en temps opportun.

Il s'agit de la boucle d'événements actuelle du navigateur.

Les tâches ordinaires sont appelées MacroTask (macro tâches) et les tâches de haute qualité sont appelées MicroTasks (micro tâches).

Les tâches macro incluent : setTimeout, setInterval, requestAnimationFrame, Ajax, fetch, code de balise de script.

Les microtâches incluent : Promise.then, MutationObserver, Object.observe.

Comment comprendre la division des tâches macro et micro ?

Les minuteries et les requêtes réseau sont une logique asynchrone courante qui informe le thread principal une fois que les autres threads ont fini de s'exécuter, ce sont donc toutes des tâches de macro.

Les trois types de tâches de haute qualité sont également faciles à comprendre. MutationObserver et Object.observe surveillent tous deux les changements dans un objet. Vous devez répondre immédiatement, sinon cela peut changer à nouveau lors de l'organisation de processus asynchrones. , appeler ensuite à la fin asynchrone est également très bon.

Voici la conception de la boucle d'événement dans le navigateur : Le mécanisme de boucle et la file d'attente des tâches sont conçus pour prendre en charge l'exécution asynchrone et résoudre le problème de l'exécution logique bloquant le thread principal. Le mécanisme de saut de file d'attente de la file d'attente MicroTask est conçu pour résoudre le problème. problème de l'exécution précoce de tâches de haute qualité .

Mais plus tard, l'environnement d'exécution de JS n'était pas seulement un navigateur, mais aussi Node.js, qui devait également résoudre ces problèmes, mais la boucle d'événement qu'il avait conçue était plus détaillée.

Event loop

Node de Node.js est un nouvel environnement d'exécution JS. Il prend également en charge la logique asynchrone, y compris les minuteries, les E/S et les requêtes réseau. Évidemment, vous pouvez également utiliser Event Loop Come and run.

Cependant, la boucle d'événement du navigateur est conçue pour les navigateurs. Pour les serveurs hautes performances, cette conception est encore un peu approximative.

Où est-ce difficile ?

La boucle d'événements du navigateur n'est divisée qu'en deux niveaux de priorité, l'un pour les macro-tâches et l'autre pour les micro-tâches. Mais il n’y a plus de priorisation entre les macro-tâches, ni entre les micro-tâches.

Et les tâches de macro de tâches Node.js ont également des priorités. Par exemple, la logique de Timer a une priorité plus élevée que celle d'IO, car en ce qui concerne le temps, plus elle est précise et la priorité de la logique de traitement est élevée. fermer les ressources C'est très faible, car s'il n'est pas fermé, il occupera tout au plus plus de mémoire et d'autres ressources, et l'impact ne sera pas grand.

La file d'attente des tâches macro a donc été divisée en cinq niveaux de priorité : Minuteries, En attente, Sondage, Vérifier et Fermer.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Expliquez ces cinq tâches macro :

Rappel des minuteries : en ce qui concerne le temps, plus l'exécution est précoce, plus elle sera précise, elle a donc la plus haute priorité et est facile à comprendre.

Pending Callback : rappel lors de la gestion du réseau, des E/S et d'autres exceptions. Certains systèmes *niux attendront que les erreurs soient signalées, elles doivent donc être traitées.

Poll Callback : Traitement des données IO et de la connexion réseau, c'est ce que le serveur gère principalement.

Check Callback : exécutez le rappel de setImmediate. La caractéristique est que cela peut être rappelé juste après l'exécution d'IO.

Close Callback : Un rappel qui ferme les ressources. Une exécution retardée ne l'affectera pas et a la priorité la plus basse.

Voici comment fonctionne la boucle d'événements de Node.js :

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Il y a une autre différence à laquelle vous devez prêter une attention particulière :

La boucle d'événements de Node.js n'est pas le genre de navigateur qui exécute une macro-tâche à la fois. , puis exécute toutes les microtâches, mais exécute un certain nombre de macrotâches de minuterie, puis exécute toutes les microtâches, puis exécute un certain nombre de macrotâches en attente, puis exécute toutes les microtâches, ainsi que les interrogations et vérifications restantes. , il en va de même pour la tâche macro Close. (Correction : c'était le cas avant le nœud 11. Après le nœud 11, il a été modifié pour chaque macro-tâche pour exécuter toutes les micro-tâches)

Pourquoi est-ce ?

En fait, c'est facile à comprendre en termes de priorité :

Supposons que la priorité de la macro-tâche dans le navigateur est 1, elle est donc exécutée dans l'ordre, c'est-à-dire une macro-tâche, toutes les micro-tâches, et puis une macro-tâche.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Et les tâches macro de Node.js ont également des priorités, donc la boucle d'événements de Node.js exécute toujours toutes les tâches macro de la priorité actuelle avant d'exécuter les micro-tâches, puis exécutez à nouveau la tâche macro prioritaire suivante .

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

C'est-à-dire un certain nombre de macro-tâches Timers, puis toutes les micro-tâches, puis un certain nombre de macro-tâches de rappel en attente, et enfin toutes les micro-tâches.

Pourquoi dit-on qu'il s'agit d'un certain montant ?

Parce que s'il y a trop de tâches macro dans une certaine étape, l'étape suivante ne sera jamais exécutée, il y a donc une limite supérieure et la boucle d'événements restante continuera à s'exécuter.

En plus de la priorité des macro-tâches, les micro-tâches sont également divisées en priorités. Il existe une micro-tâche supplémentaire de haute priorité de process.nextTick, qui s'exécute avant toutes les micro-tâches ordinaires.

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Ainsi, le processus complet de la boucle d'événement Node.js est comme ceci :

  • Étape Timers : exécutez un certain nombre de minuteries, c'est-à-dire les rappels setTimeout, setInterval, s'il y en a trop, laissez jusqu'à la prochaine fois Exécuter
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires
  • Phase d'attente : exécutez un certain nombre de rappels d'E/S et d'exceptions réseau S'il y en a trop, laissez-les à la prochaine exécution.
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires
  • Phase d'inactivité/préparation : une phase utilisée en interne
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires
  • Phase d'interrogation : Exécutez un certain nombre de rappels de données de fichiers et de rappels de connexion réseau. S'il y en a trop, laissez-les à l'exécution suivante. S'il n'y a pas de rappel IO et qu'il n'y a pas de minuteries et de rappels de phase de vérification à traiter, bloquez simplement ici et attendez les événements IO
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires
  • Phase de vérification : Exécutez un certain nombre de rappels setImmediate s'il y en a trop, ils seront exécutés la prochaine fois.
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires
  • Phase de fermeture : exécutez un certain nombre de rappels d'événements de fermeture s'il y en a trop, laissez-les pour la prochaine exécution.
  • Microtâches : exécutez toutes les microtâches nextTick, puis exécutez d'autres microtâches ordinaires

Par rapport à la boucle d'événement dans le navigateur, c'est évidemment beaucoup plus compliqué, mais après notre analyse précédente, nous pouvons aussi comprendre :

Noeud. js a hiérarchisé les tâches macro, qui sont les minuteries, en attente, l'interrogation, la vérification et la fermeture, de haut en bas, et a également divisé les micro-tâches, c'est-à-dire les micro-tâches nextTick et d'autres micro-tâches. Le processus d'exécution consiste à exécuter d'abord un certain nombre de macrotâches de la priorité actuelle (en laissant le reste pour le cycle suivant), puis à exécuter les microtâches de process.nextTick, puis à exécuter des microtâches ordinaires, puis à exécuter un certain nombre de la priorité suivante. . nombre de tâches macro. . Ce cycle continue. Il existe également une étape Idle/Prepare pour la logique interne de Node.js, vous n'avez donc pas à vous en soucier.

Modification de la manière d'exécuter une tâche de macro à la fois dans la boucle d'événement du navigateur, ce qui permet d'exécuter plus tôt les tâches de macro hautement prioritaires, mais définit également une limite supérieure pour empêcher l'étape suivante de ne pas être exécutée.

Il y a un autre point auquel prêter une attention particulière, qui est l'étape d'interrogation : Si vous exécutez l'étape d'interrogation et constatez que la file d'attente d'interrogation est vide et qu'il n'y a aucune tâche à exécuter dans la file d'attente des minuteries et la file d'attente de vérification, alors vous serez bloqué et attendez ici l'événement IO au lieu de rester inactif. Cette conception est également due au fait que le serveur gère principalement les IO, et le blocage ici peut répondre aux IO plus tôt.

La boucle d'événements complète de Node.js ressemble à ceci :

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Comparez la boucle d'événements du navigateur :

Découvrez pourquoi les navigateurs et Node.js ont conçu EventLoop de cette façon !

Les idées générales de conception de la boucle d'événements des deux environnements d'exécution JS sont similaires, sauf ce Node La boucle d'événements de .js effectue une division plus fine des macro-tâches et des micro-tâches, ce qui est facile à comprendre. Après tout, l'environnement de Node.js est différent de celui des navigateurs. Plus important encore, les exigences de performances. du serveur sera plus élevé.

Résumé

JavaScript a d'abord été utilisé pour écrire une logique d'interaction de page Web afin d'éviter le problème de synchronisation de plusieurs threads modifiant le DOM en même temps, il a été conçu comme un seul thread afin de résoudre le blocage. problème d'un seul thread, une couche de logique de planification a été ajoutée, c'est-à-dire une boucle de boucle et une file d'attente de tâches, permettant à d'autres threads de s'exécuter, prenant ainsi en charge l'asynchrone. Ensuite, afin de prendre en charge la planification des tâches hautement prioritaires, des files d'attente de micro-tâches ont été introduites. Il s'agit du mécanisme de boucle d'événements du navigateur : une macro-tâche est exécutée à chaque fois, puis toutes les micro-tâches sont exécutées.

Node.js est également un environnement d'exécution JS. Si vous souhaitez prendre en charge le mode asynchrone, vous devez également utiliser Event Loop. Cependant, l'environnement du serveur est plus complexe et a des exigences de performances plus élevées, donc Node.js a été plus performant. -Tâches macro et micro à granularité :

Node.js est divisé en 5 types de tâches macro, à savoir les minuteries, en attente, d'interrogation, de vérification et de fermeture. Deux types de microtâches sont divisés, à savoir les microtâches process.nextTick et les autres microtâches.

Le processus de boucle d'événement de Node.js consiste à exécuter un certain nombre de tâches de macro dans l'étape en cours (le reste sera exécuté dans la boucle suivante), puis à exécuter toutes les micro-tâches. Il y a des minuteries, en attente, inactives. /Préparer, Sonder, Vérifier, Fermer 6 étapes. (Correction : c'était le cas avant le nœud 11. Après le nœud 11, il a été modifié pour chaque macro-tâche pour exécuter toutes les micro-tâches)

L'étape Idle/Prepare est utilisée en interne par Node.js, alors ne vous inquiétez pas il.

Une attention particulière doit être accordée à la phase d'interrogation. Si la file d'attente d'interrogation est vide et que les minuteries et les files d'attente de contrôle sont également vides, elle sera bloquée ici en attente d'IO jusqu'à ce qu'il y ait des rappels dans les minuteries et les files d'attente de vérification avant de continuer le processus. boucle.

Event Loop est un ensemble de logique de planification conçu par JS pour prendre en charge la priorité asynchrone et des tâches. Il a différentes conceptions pour différents environnements tels que les navigateurs et Node.js (principalement en raison de la granularité différente des priorités des tâches de Node js). des environnements plus complexes et ont des exigences de performances plus élevées, de sorte que la conception de la boucle d'événement est plus complexe.

Pour plus de connaissances sur les nœuds, veuillez visiter :

tutoriel Nodejs ! !

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer