Maison interface Web js tutoriel Analyser le mécanisme de boucle d'événements de Node.js

Analyser le mécanisme de boucle d'événements de Node.js

Oct 20, 2018 pm 04:25 PM
es6 javascript node.js

Le contenu de cet article concerne l'analyse du mécanisme de boucle d'événements de Node.js. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Dans l'article sur le navigateur, le mécanisme de boucle d'événements et certains concepts associés ont été présentés en détail, mais c'est principalement pour la recherche côté navigateur. Est-ce la même chose pour l'environnement Node ? Jetons d'abord un coup d'œil à une démo :

setTimeout(()=>{
    console.log('timer1')
    Promise.resolve().then(function() {
        console.log('promise1')
    })}, 0)setTimeout(()=>{
    console.log('timer2')
    Promise.resolve().then(function() {
        console.log('promise2')
    })}, 0)
Copier après la connexion

Compilez-la et exécutez-la à l'œil nu. Le résultat dans le navigateur est le suivant. Vous connaissez déjà la vérité, je n'entrerai donc pas dans les détails. ici.

timer1
promise1
timer2
promise2
Copier après la connexion

Ensuite, exécutez-le sous Node, hein. . . Étrange, les résultats d'exécution sont différents de ceux du navigateur~

timer1
timer2
promise1
promise2
Copier après la connexion

L'exemple montre que le mécanisme de boucle d'événements du navigateur et de Node.js est différent, jetons-y un coup d'oeil~

Traitement des événements Node.js

Node.js utilise V8 comme moteur d'analyse js et utilise sa propre libuv conçue pour le traitement des E/S. libuv est une couche d'abstraction multiplateforme basée sur les événements. encapsule certaines fonctionnalités sous-jacentes de différents systèmes d'exploitation et fournit une API unifiée au monde extérieur. Le mécanisme de boucle d'événements y est également implémenté. Référence du code source principal :

int uv_run(uv_loop_t* loop, uv_run_mode mode) {
  int timeout;
  int r;
  int ran_pending;
  r = uv__loop_alive(loop);
  if (!r)
    uv__update_time(loop);
  while (r != 0 && loop->stop_flag == 0) {
    uv__update_time(loop);
    // timers阶段
    uv__run_timers(loop);
    // I/O callbacks阶段
    ran_pending = uv__run_pending(loop);
    // idle阶段
    uv__run_idle(loop);
    // prepare阶段
    uv__run_prepare(loop);
    timeout = 0;
    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
      timeout = uv_backend_timeout(loop);
    // poll阶段
    uv__io_poll(loop, timeout);
    // check阶段
    uv__run_check(loop);
    // close callbacks阶段
    uv__run_closing_handles(loop);
    if (mode == UV_RUN_ONCE) {
      uv__update_time(loop);
      uv__run_timers(loop);
    }
    r = uv__loop_alive(loop);
    if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
      break;
  }
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;
  return r;
}
Copier après la connexion

Selon l'introduction officielle de Node. js, chaque boucle d'événement contient Il y a 6 étapes, correspondant à l'implémentation dans le code source de libuv, comme le montre la figure ci-dessous

Analyser le mécanisme de boucle dévénements de Node.js

étape timers : Cette étape exécute le rappel de la minuterie (setTimeout, setInterval)

Phase de rappels d'E/S : exécute certaines erreurs d'appel système, telles que les rappels d'erreurs de communication réseau

inactif, phase de préparation : utilisée uniquement en interne par le nœud

phase d'interrogation : obtenez un nouvel événement d'E/S, dans des conditions appropriées, le nœud bloquera ici

phase de vérification : exécutez le rappel de setImmediate()

phase de rappels de fermeture : exécutez la fermeture rappel d'événement du socket

Notre objectif Il suffit de regarder les trois étapes des minuteries, d'interroger et de vérifier, car la plupart des tâches asynchrones du développement quotidien sont traitées dans ces trois étapes.

phase des minuteries

les minuteries sont la première phase de la boucle d'événements, Node Vérifiera s'il y a un minuteur expiré, et si c'est le cas, poussera son rappel dans la file d'attente des tâches du minuteur pour attendre l'exécution. En fait, Node. Il n'y a aucune garantie que le minuteur sera exécuté immédiatement lorsque l'heure prédéfinie est atteinte, car la vérification de l'expiration du minuteur par Node n'est pas nécessairement fiable. Elle sera affectée par d'autres programmes en cours d'exécution sur la machine, ou le thread principal n'est pas inactif. cette fois-là. Par exemple, dans le code suivant, l'ordre d'exécution de setTimeout() et setImmediate() est incertain.

setTimeout(() => {
  console.log('timeout')
  }, 0)
  setImmediate(() => {
  console.log('immediate')
  })
Copier après la connexion

Mais si vous les mettez dans un rappel d'E/S, setImmediate() doit être exécuté en premier, car la phase d'interrogation est suivie de la phase de vérification.

Phase d'interrogation

La phase d'interrogation a principalement deux fonctions :

Traitement des événements dans la file d'attente d'interrogation

Lorsqu'un minuteur a expiré, exécuter sa fonction de rappel

la boucle paire exécutera de manière synchrone les rappels dans la file d'attente d'interrogation jusqu'à ce que la file d'attente soit vide ou que les rappels exécutés atteignent la limite supérieure du système (la limite supérieure est inconnue), puis la boucle paire vérifiera si il existe un prédéfini setImmediate(), divisé en deux situations :

S'il existe un prédéfini setImmediate(), la boucle d'événements mettra fin à la phase d'interrogation et entrera dans la phase de vérification, et exécutera la file d'attente des tâches de la vérification phase

S'il n'y a pas de setImmediate() prédéfini, la boucle d'événement se bloquera et attendra à ce stade

Notez un détail, aucun setImmediate() ne provoquera l'événement La boucle est bloquée dans la phase d'interrogation, le timer précédemment réglé ne pourrait-il donc pas être exécuté ? Ainsi, lors de la phase de sondage, l'événement La boucle aura un mécanisme de vérification pour vérifier si la file d'attente du minuteur est vide. Si la file d'attente du minuteur n'est pas vide, l'événement. La boucle démarre le prochain tour de boucle d'événements, c'est-à-dire entre à nouveau dans la phase de minuterie.

phase de vérification

Le rappel de setImmediate() sera ajouté à la file d'attente de vérification. À partir du diagramme de phase de la boucle d'événements, nous pouvons savoir que l'ordre d'exécution de la phase de vérification est après l'interrogation. phase.

Résumé

Chaque étape de la boucle d'événements a une file d'attente de tâches

Lorsque la boucle d'événements atteint une certaine étape, la file d'attente de tâches de cette étape sera exécutée jusqu'à ce que la file d'attente est effacé. Ou lorsque le rappel exécuté atteint la limite du système, il passera à l'étape suivante

Lorsque toutes les étapes sont exécutées en séquence une fois, la boucle d'événements est dite avoir terminé un tick

C'est logique, mais sans la démo, je ne comprends toujours pas complètement. Je suis anxieux, maintenant !

const fs = require('fs')fs.readFile('test.txt', () => {
  console.log('readFile')
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  setImmediate(() => {
    console.log('immediate')
  })
  })
Copier après la connexion

Il ne devrait y avoir aucun doute sur le résultat de l'exécution

readFile
immediate
timeout
Copier après la connexion

Différences entre Node.js et la boucle d'événement du navigateur

Revue de l'article précédent, dans le navigateur environnement , la file d'attente des tâches de la microtâche est exécutée après l'exécution de chaque macrotâche.

Analyser le mécanisme de boucle dévénements de Node.js

Dans Node.js, les microtâches seront exécutées entre différentes étapes de la boucle d'événements, c'est-à-dire qu'après l'exécution d'une étape, les tâches de la file d'attente des microtâches seront exécutées .

Analyser le mécanisme de boucle dévénements de Node.js

Revue de la démo

En revue la démo au début de l'article, le script global (main()) est exécuté, et les deux minuteries sont successivement placées dans la file d'attente des minuteries, main() est exécutée, la pile d'appels est inactive et la file d'attente des tâches commence à s'exécuter

;

Analyser le mécanisme de boucle dévénements de Node.js

首先进入timers阶段,执行timer1的回调函数,打印timer1,并将promise1.then回调放入microtask队列,同样的步骤执行timer2,打印timer2;

至此,timer阶段执行结束,event loop进入下一个阶段之前,执行microtask队列的所有任务,依次打印promise1、promise2。

对比浏览器端的处理过程:

Analyser le mécanisme de boucle dévénements de Node.js

process.nextTick() VS setImmediate()

In essence, the names should be swapped. process.nextTick() fires more immediately than setImmediate()

来自官方文档有意思的一句话,从语义角度看,setImmediate() 应该比 process.nextTick() 先执行才对,而事实相反,命名是历史原因也很难再变。

process.nextTick() 会在各个事件阶段之间执行,一旦执行,要直到nextTick队列被清空,才会进入到下一个事件阶段,所以如果递归调用 process.nextTick(),会导致出现I/O starving(饥饿)的问题,比如下面例子的readFile已经完成,但它的回调一直无法执行:

const fs = require('fs')const starttime = Date.now()let endtime
fs.readFile('text.txt', () => {
  endtime = Date.now()
  console.log('finish reading time: ', endtime - starttime)})let index = 0function handler () {
  if (index++ >= 1000) return
  console.log(`nextTick ${index}`)
  process.nextTick(handler)
  // console.log(`setImmediate ${index}`)
  // setImmediate(handler)}handler()
Copier après la connexion

process.nextTick()的运行结果:

nextTick 1
nextTick 2
......
nextTick 999
nextTick 1000
finish reading time: 170
Copier après la connexion

替换成setImmediate(),运行结果:

setImmediate 1
setImmediate 2
finish reading time: 80
......
setImmediate 999
setImmediate 1000
Copier après la connexion

这是因为嵌套调用的 setImmediate() 回调,被排到了下一次event loop才执行,所以不会出现阻塞。

总结

1、Node.js 的事件循环分为6个阶段

2、浏览器和Node 环境下,microtask 任务队列的执行时机不同

Node.js中,microtask 在事件循环的各个阶段之间执行

浏览器端,microtask 在事件循环的 macrotask 执行完之后执行

3、递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()

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 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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Commandes de chat et comment les utiliser
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment mettre en œuvre un système de reconnaissance vocale en ligne à l'aide de WebSocket et JavaScript Comment mettre en œuvre un système de reconnaissance vocale en ligne à l'aide de WebSocket et JavaScript Dec 17, 2023 pm 02:54 PM

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de reconnaissance vocale en ligne Introduction : Avec le développement continu de la technologie, la technologie de reconnaissance vocale est devenue une partie importante du domaine de l'intelligence artificielle. Le système de reconnaissance vocale en ligne basé sur WebSocket et JavaScript présente les caractéristiques d'une faible latence, d'un temps réel et d'une multiplateforme, et est devenu une solution largement utilisée. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de reconnaissance vocale en ligne.

WebSocket et JavaScript : technologies clés pour mettre en œuvre des systèmes de surveillance en temps réel WebSocket et JavaScript : technologies clés pour mettre en œuvre des systèmes de surveillance en temps réel Dec 17, 2023 pm 05:30 PM

WebSocket et JavaScript : technologies clés pour réaliser des systèmes de surveillance en temps réel Introduction : Avec le développement rapide de la technologie Internet, les systèmes de surveillance en temps réel ont été largement utilisés dans divers domaines. L'une des technologies clés pour réaliser une surveillance en temps réel est la combinaison de WebSocket et de JavaScript. Cet article présentera l'application de WebSocket et JavaScript dans les systèmes de surveillance en temps réel, donnera des exemples de code et expliquera leurs principes de mise en œuvre en détail. 1. Technologie WebSocket

Comment utiliser JavaScript et WebSocket pour mettre en œuvre un système de commande en ligne en temps réel Comment utiliser JavaScript et WebSocket pour mettre en œuvre un système de commande en ligne en temps réel Dec 17, 2023 pm 12:09 PM

Introduction à l'utilisation de JavaScript et de WebSocket pour mettre en œuvre un système de commande en ligne en temps réel : avec la popularité d'Internet et les progrès de la technologie, de plus en plus de restaurants ont commencé à proposer des services de commande en ligne. Afin de mettre en œuvre un système de commande en ligne en temps réel, nous pouvons utiliser les technologies JavaScript et WebSocket. WebSocket est un protocole de communication full-duplex basé sur le protocole TCP, qui peut réaliser une communication bidirectionnelle en temps réel entre le client et le serveur. Dans le système de commande en ligne en temps réel, lorsque l'utilisateur sélectionne des plats et passe une commande

Comment mettre en œuvre un système de réservation en ligne à l'aide de WebSocket et JavaScript Comment mettre en œuvre un système de réservation en ligne à l'aide de WebSocket et JavaScript Dec 17, 2023 am 09:39 AM

Comment utiliser WebSocket et JavaScript pour mettre en œuvre un système de réservation en ligne. À l'ère numérique d'aujourd'hui, de plus en plus d'entreprises et de services doivent fournir des fonctions de réservation en ligne. Il est crucial de mettre en place un système de réservation en ligne efficace et en temps réel. Cet article explique comment utiliser WebSocket et JavaScript pour implémenter un système de réservation en ligne et fournit des exemples de code spécifiques. 1. Qu'est-ce que WebSocket ? WebSocket est une méthode full-duplex sur une seule connexion TCP.

JavaScript et WebSocket : créer un système efficace de prévisions météorologiques en temps réel JavaScript et WebSocket : créer un système efficace de prévisions météorologiques en temps réel Dec 17, 2023 pm 05:13 PM

JavaScript et WebSocket : Construire un système efficace de prévisions météorologiques en temps réel Introduction : Aujourd'hui, la précision des prévisions météorologiques revêt une grande importance pour la vie quotidienne et la prise de décision. À mesure que la technologie évolue, nous pouvons fournir des prévisions météorologiques plus précises et plus fiables en obtenant des données météorologiques en temps réel. Dans cet article, nous apprendrons comment utiliser la technologie JavaScript et WebSocket pour créer un système efficace de prévisions météorologiques en temps réel. Cet article démontrera le processus de mise en œuvre à travers des exemples de code spécifiques. Nous

Comment utiliser insertBefore en javascript Comment utiliser insertBefore en javascript Nov 24, 2023 am 11:56 AM

Utilisation : En JavaScript, la méthode insertBefore() est utilisée pour insérer un nouveau nœud dans l'arborescence DOM. Cette méthode nécessite deux paramètres : le nouveau nœud à insérer et le nœud de référence (c'est-à-dire le nœud où le nouveau nœud sera inséré).

Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Jan 05, 2024 pm 06:08 PM

Tutoriel JavaScript : Comment obtenir le code d'état HTTP, des exemples de code spécifiques sont requis Préface : Dans le développement Web, l'interaction des données avec le serveur est souvent impliquée. Lors de la communication avec le serveur, nous devons souvent obtenir le code d'état HTTP renvoyé pour déterminer si l'opération a réussi et effectuer le traitement correspondant en fonction de différents codes d'état. Cet article vous apprendra comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournira quelques exemples de codes pratiques. Utilisation de XMLHttpRequest

JavaScript et WebSocket : créer un système de traitement d'images en temps réel efficace JavaScript et WebSocket : créer un système de traitement d'images en temps réel efficace Dec 17, 2023 am 08:41 AM

JavaScript est un langage de programmation largement utilisé dans le développement Web, tandis que WebSocket est un protocole réseau utilisé pour la communication en temps réel. En combinant les puissantes fonctions des deux, nous pouvons créer un système efficace de traitement d’images en temps réel. Cet article présentera comment implémenter ce système à l'aide de JavaScript et WebSocket, et fournira des exemples de code spécifiques. Tout d’abord, nous devons clarifier les exigences et les objectifs du système de traitement d’images en temps réel. Supposons que nous disposions d'un appareil photo capable de collecter des données d'image en temps réel.

See all articles