Maison  >  Article  >  interface Web  >  Événement Node.js piloté_node.js

Événement Node.js piloté_node.js

WBOY
WBOYoriginal
2016-05-16 15:54:071267parcourir

Présentation de la mise en œuvre événementielle de Node.js

Bien que les « événements » ne soient pas (et ne soient pas nécessaires) clairement définis dans la norme ECMAScript, les événements constituent un mécanisme extrêmement important dans les navigateurs, donnant à JavaScript la capacité de répondre aux opérations des utilisateurs et aux modifications du DOM dans Node ; , le modèle asynchrone basé sur les événements est à la base de sa haute capacité de concurrence.

Apprendre JavaScript nécessite également de comprendre sa plate-forme d'exécution. Afin de mieux comprendre le modèle d'événement de JavaScript, je prévois de commencer par le code source du nœud et du moteur de navigateur, d'analyser son implémentation sous-jacente et d'organiser mon analyse dans une série d'articles de blog. ; D'une part, c'est une note, et d'autre part, j'espère communiquer avec tout le monde. S'il y a des omissions et des biais dans l'analyse et la compréhension, j'espère que vous me corrigerez.

Une brève description du modèle événementiel

Il existe déjà de nombreux bons articles expliquant le modèle d'événement JavaScript lui-même. On peut dire qu'il s'agit déjà d'un sujet peu discuté. Ici, je n'en parlerai que brièvement et fournirai des liens vers quelques bons articles.

Comment le programme répond aux événements

Notre programme répond aux événements extérieurs des deux manières suivantes :

Interruption

Le système d'exploitation gère les entrées du clavier et d'autres éléments matériels via des interruptions. L'avantage de cette méthode est que même sans multithread, nous pouvons exécuter notre code en toute sécurité. Une fois que le processeur a reçu le signal d'interruption, il effectuera automatiquement le transfert pour exécuter le code. correspondant Une fois le gestionnaire d'interruption terminé, l'environnement d'exécution du code d'origine sera restauré et l'exécution continuera. Cette méthode nécessite une prise en charge matérielle et est généralement encapsulée par le système d'exploitation.

Sondage

Boucle pour détecter si un événement se produit, et si c'est le cas, exécuter le gestionnaire correspondant. Cela s’applique aussi bien au développement de bas niveau qu’à celui de niveau supérieur.
Les programmes Windows Windows doivent écrire le code suivant dans le thread principal, généralement appelé boucle de messages :

MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}

La boucle de messages détecte en permanence s'il y a des messages (opérations de l'interface utilisateur de l'utilisateur, messages système, etc.). Si tel est le cas, elle distribue les messages et appelle la fonction de rappel correspondante pour le traitement.
Un inconvénient de la méthode d'interrogation est que si des opérations fastidieuses sont effectuées dans la boucle de messages du thread principal, le programme ne peut pas répondre aux nouveaux messages en temps opportun. Ceci est évident en JavaScript et sera mentionné plus tard, avec ses solutions.

Cependant, il n'existe pas de code de boucle de message similaire en JavaScript. Nous enregistrons simplement l'événement et attendons qu'il soit appelé. En effet, le navigateur et Node, en tant que plates-formes d'exécution, ont déjà implémenté la boucle d'événements. Le code JavaScript n'a pas besoin d'être impliqué dans ce processus. Il lui suffit d'attendre tranquillement en tant qu'appelé.

Boucle d'événement dans Node

Regardez l'implémentation de la boucle d'événements via le code source de Node

Node utilise V8 comme moteur d'exécution JavaScript et utilise libuv pour implémenter des E/S asynchrones pilotées par événements. Sa boucle d'événements utilise la boucle d'événements par défaut de libuv.

Dans src/node.cc,

Environment* env = CreateEnvironment(
    node_isolate,
    uv_default_loop(),
    context,
    argc,
    argv,
    exec_argc,
    exec_argv);

Ce code établit un environnement d'exécution de nœud. Vous pouvez voir uv_default_loop() dans la troisième ligne. Il s'agit d'une fonction de la bibliothèque libuv elle-même et du default_loop_struct qu'elle contient, et renvoie un pointeur vers celle-ci. Pointeur default_loop_ptr.
Ensuite, Node chargera l'environnement d'exécution et effectuera quelques opérations de configuration, puis lancera la boucle d'événements :

bool more;
do {
 more = uv_run(env->event_loop(), UV_RUN_ONCE);
 if (more == false) {
  EmitBeforeExit(env);
  // Emit `beforeExit` if the loop became alive either after emitting
  // event, or after running some callbacks.
  more = uv_loop_alive(env->event_loop());
  if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
   more = true;
 }
} while (more == true);
code = EmitExit(env);
RunAtExit(env);
...

plus est utilisé pour déterminer s'il faut passer au cycle suivant.

env->event_loop() renverra le default_loop_ptr précédemment enregistré dans env, et la fonction uv_run démarrera la boucle d'événements de libuv dans le mode UV_RUN_ONCE spécifié. Dans ce mode, uv_run traitera au moins un événement : cela signifie que s'il n'y a aucun événement d'E/S à traiter dans la file d'attente d'événements actuelle, uv_run bloquera jusqu'à ce qu'il y ait un événement d'E/S à traiter. , ou le minuteur suivant. Le temps est écoulé. S'il n'y a actuellement aucun événement d'E/S ni aucun événement de minuterie, uv_run renvoie false.

Next Node décidera de la prochaine étape en fonction de la situation de plus :

Si davantage est vrai, continuez à exécuter la boucle suivante.

Si more est faux, cela signifie qu'il n'y a aucun événement en attente de traitement. EmitBeforeExit(env); déclenche l'événement 'beforeExit' du processus, vérifie et traite la fonction de traitement correspondante et sort directement de la boucle. après l'achèvement.

Enfin, l'événement 'exit' est déclenché, la fonction de rappel correspondante est exécutée, l'opération Node se termine et certaines opérations de libération de ressources seront effectuées ultérieurement.

Dans libuv, les événements du timer sont traités directement dans la boucle d'événements, tandis que les événements d'E/S sont divisés en deux catégories :

Les E/S réseau utilisent la solution d'E/S non bloquante fournie par le système, telle que epoll sous Linux et IOCP sous Windows.

Il n'existe pas de (bonne) solution système pour les opérations sur les fichiers et les opérations DNS, donc libuv a construit son propre pool de threads pour effectuer le blocage des E/S.

De plus, nous pouvons également lancer la fonction personnalisée dans le pool de threads pour l'exécuter. Une fois l'opération terminée, le thread principal exécutera la fonction de rappel correspondante. Cependant, Node n'a pas ajouté cette fonction à JavaScript, ce qui signifie que. il est uniquement impossible d'ouvrir de nouveaux threads en JavaScript pour une exécution parallèle à l'aide de Node natif.

Ce qui précède représente l’intégralité du contenu de cet article, j’espère que vous l’aimerez tous.

Déclaration:
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