Nous avons expliqué pourquoi Node JS est monothread et également multithread dans notre article intitulé "Node Internals". Cela vous donnera une base solide sur l’architecture de Node et préparera le terrain pour comprendre la magie de l’Event Loop !
Node js pourrait être considéré comme monothread en raison de la boucle d'événement. Mais qu’est-ce que la boucle événementielle ?
Je commence toujours par l'analogie du restaurant car je pense qu'il devient facile de comprendre les détails techniques.
Ainsi, au restaurant, le chef principal prend les commandes de la liste de commandes et les remet à l'équipe d'assistants. Lorsque la nourriture est prête, le chef sert la nourriture. Si des clients VIP viennent, le chef donne la priorité à cette commande.
Si nous prenons cette analogie en considération, alors nous pouvons dire que...
Dans le contexte de la boucle d'événement Node JS.
Chef est la boucle d'événements qui gère les tâches et délègue le travail.
Team of Assistance est un thread de travail ou le système d'exploitation qui gère l'exécution des tâches qui leur sont déléguées.
La liste de commandes est une file d'attente pour les tâches en attente de leur tour.
Le client VIP est une microtâche qui a une priorité élevée et est effectuée avant les tâches régulières.
Pour comprendre la boucle d'événement, nous devons d'abord comprendre la différence entre les microtâches et les macrotâches.
Microtâche désigne les tâches qui ont une priorité élevée et sont exécutées une fois le code Javascript en cours d'exécution terminé, mais avant de passer à la phase suivante de la boucle d'événements.
Exemple :
Il s'agit de tâches de moindre priorité mises en file d'attente pour être exécutées ultérieurement dans la boucle d'événements.
Exemple :
Lorsque nous exécutons des tâches asynchrones dans Node.js, la boucle d'événements est au cœur de tout.
Grâce à l'Event Loop, Node.js peut effectuer efficacement des opérations d'E/S non bloquantes. Il y parvient en déléguant des tâches fastidieuses au système d'exploitation ou aux threads de travail. Une fois les tâches terminées, leurs rappels sont traités de manière organisée, garantissant une exécution fluide sans bloquer le thread principal.
C'est la magie qui permet à Node.js de gérer plusieurs tâches simultanément tout en restant monothread.
Il y a six phases dans une boucle d'événement et chaque phase a sa propre file d'attente, qui contient des types de tâches spécifiques.
1.Phase des minuteries
Dans cette phase, les rappels liés à la minuterie sont gérés, tels que setTimeout et setInterval.
Node js vérifie dans la file d'attente du minuteur les rappels dont le délai a expiré.
Si un délai de minuterie est respecté, son rappel est ajouté à cette file d'attente pour exécution.
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
Sortie :
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
2.Phase de rappel d'E/S
Le but de cette phase est d'exécuter des rappels pour les opérations d'E/S (Entrée/Sortie) terminées, telles que la lecture ou l'écriture de fichiers, l'interrogation de bases de données, la gestion des requêtes réseau et d'autres tâches d'E/S asynchrones.
Lorsqu'une opération d'E/S asynchrone dans Node.js (comme la lecture d'un fichier à l'aide de fs.readFile) survient, l'opération est déléguée au système d'exploitation ou aux threads de travail. Ces tâches d'E/S sont exécutées en dehors du thread principal de manière non bloquante. Une fois la tâche terminée, une fonction de rappel est déclenchée pour traiter les résultats.
La phase de rappels d'E/S est l'endroit où ces rappels sont mis en file d'attente pour être exécutés une fois l'opération terminée.
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
Sortie
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
3.Phase de ralenti
Dans cette phase, aucun travail défini par l'utilisateur n'est effectué. Au lieu de cela, la boucle d'événements de phase se prépare pour les phases suivantes. seuls les ajustements internes sont effectués dans cette phase.
4.Phase de sondage
La phase d'interrogation vérifie s'il y a des événements d'E/S en attente (comme l'activité réseau ou les événements du système de fichiers) qui doivent être traités. Il exécutera immédiatement les rappels associés à ces événements.
Si aucun événement d'E/S n'est en attente, la phase d'interrogation peut entrer dans un état de blocage.
Dans cet état de blocage, Node.js attendra simplement l'arrivée de nouveaux événements d'E/S. Cet état de blocage est ce qui rend Node.js non bloquant : il attend que de nouveaux événements d'E/S déclenchent des exécutions de rappel, gardant le thread principal libre pour d'autres tâches entre-temps.
Tous les rappels pour les opérations d'E/S terminées (telles que fs.readFile, les requêtes HTTP ou les requêtes de base de données) sont exécutés au cours de cette phase. Ces opérations d'E/S peuvent avoir été lancées lors de phases précédentes (comme la phase des minuteries ou la phase de rappels d'E/S) et sont maintenant terminées.
S'il y a des minuteries définies avec setTimeout ou setInterval, Node.js vérifiera si des minuteries ont expiré et si leurs rappels associés doivent être exécutés. Si les minuteries ont expiré, leurs rappels sont déplacés vers la file d'attente de rappel, mais ils ne seront traités qu'à la phase suivante, qui est la phase des minuteries.
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
Sortie :
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
5.Phase de vérification
Une fois que la phase de sondage a terminé ses tâches. Cette phase gère principalement l'exécution des rappels setImmediate, qui sont programmés pour s'exécuter immédiatement après le traitement des événements d'E/S dans la phase d'interrogation.
Les rappels setImmediate sont souvent utilisés lorsque vous souhaitez effectuer une action après le cycle de boucle d'événements en cours, par exemple pour vous assurer qu'une tâche est exécutée une fois que le système n'est pas occupé à traiter les événements d'E/S.
La phase de vérification a une priorité plus élevée sur la phase Timers (qui gère setTimeout et setInterval). Cela signifie que les rappels setImmediate seront toujours exécutés avant les minuteries, même si leurs minuteries ont expiré.
setImmediate garantit que son rappel s'exécutera après le cycle d'E/S en cours et avant le prochain cycle de minuterie. Cela peut être important lorsque vous souhaitez vous assurer que les tâches liées aux E/S sont terminées avant d'exécuter d'autres tâches.
console.log('Start'); setTimeout(() => { console.log('Timer 1 executed after 1 second'); }, 1000); setTimeout(() => { console.log('Timer 2 executed after 0.5 seconds'); }, 500); let count = 0; const intervalId = setInterval(() => { console.log('Interval callback executed'); count++; if (count === 3) { clearInterval(intervalId); console.log('Interval cleared'); } }, 1000); console.log('End');
Sortie :
Start End Timer 2 executed after 0.5 seconds Timer 1 executed after 1 second Interval callback executed Interval callback executed Interval callback executed Interval cleared
6.phase de fermeture
La phase de rappels de fermeture s'exécute généralement lorsqu'une application doit être nettoyée avant de quitter ou de s'arrêter.
Cette phase traite des événements et des tâches qui doivent être exécutés une fois qu'une ressource système, comme une socket réseau ou un descripteur de fichier, n'est plus nécessaire.
Sans cette phase, une application peut laisser des descripteurs de fichiers, des connexions réseau ou d'autres ressources ouverts, ce qui peut entraîner des fuites de mémoire, une corruption de données ou d'autres problèmes.
const fs = require('fs'); console.log('Start'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file:', err); return; } console.log('File contents:', data); }); console.log('Middle'); setTimeout(() => { console.log('Simulated network request completed'); }, 0); console.log('End');
Sortie :
Start Middle End Simulated network request completed File contents: (contents of the example.txt file)
Il y a une phase spéciale supplémentaire dans la boucle d'événement de Node JS.
File d'attente des microtâches
process.nextTick() et promet d'exécuter ses rappels dans une phase spéciale dans la boucle d'événement.
process.nextTick() planifie l'exécution d'un rappel immédiatement après la fin de l'opération en cours, mais avant que la boucle d'événements ne passe à la phase suivante.
process.nextTick() ne fait partie d'aucune phase de la boucle d'événements. Au lieu de cela, il possède sa propre file d'attente interne qui est exécutée juste après le code synchrone en cours d'exécution et avant l'entrée d'une phase dans la boucle d'événements.
Il est exécuté après l'opération en cours mais avant les E/S, setTimeout ou d'autres tâches planifiées dans la boucle d'événements.
Les promesses ont une priorité inférieure à process.nextTick() et sont traitées après tous les rappels process.nextTick().
const fs = require('fs'); const https = require('https'); console.log('Start'); fs.readFile('file1.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file1:', err); return; } console.log('File1 content:', data); }); fs.readFile('file2.txt', 'utf8', (err, data) => { if (err) { console.log('Error reading file2:', err); return; } console.log('File2 content:', data); }); https.get('https://jsonplaceholder.typicode.com/todos/1', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { console.log('HTTP Response:', data); }); }); console.log('End');
Sortie :
Start End File1 content: (contents of file1.txt) File2 content: (contents of file2.txt) HTTP Response: (JSON data from the HTTP request)
Maintenant, vous avez une idée globale du fonctionnement de la boucle d'événement.
Je vous pose une question à laquelle vous pouvez répondre dans les commentaires.
const fs = require('fs'); console.log('Start'); fs.readFile('somefile.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log('File content:', data); }); setImmediate(() => { console.log('Immediate callback executed'); }); setTimeout(() => { console.log('Timeout callback executed'); }, 0); console.log('End');
Merci.
En attente de votre réponse.
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!