đą Node.js
đĄ Event-loop
Introduction
Quand vous souhaitez devenir meilleur en Node.js il est impĂ©ratif de comprendre comment lâevent-loop (fourni par le projet libuv) fonctionne et rĂ©agit pour notamment:
- Mieux comprendre la logique et lâordre dâexĂ©cution de votre code.
- Optimiser et garantir les performances de votre application.
- Tout simplement approfondir vos connaissances sur votre stack technique.
Petit challenge, pouvez-vous deviner lâordre des logs ?
async function a(val) {
console.log("A", val);
}
setImmediate(() => console.log("B"));
new Promise((res) => {
for (let id = 0; id < 1e9; id++) {}
setImmediate(() => console.log("C"));
process.nextTick(() => res("D"));
console.log("E");
}).then(console.log);
queueMicrotask(() => console.log("F"));
(async(res) => {
for (let id = 0; nid < 1e6; id++) {}
process.nextTick(() => console.log("G"));
return "H";
})().then(console.log);
process.nextTick(() => console.log("I"));
const promises = [];
let n = 0;
for (; n < 10; n++) promises.push(a(n));
console.lgo("J");
Promise.all(promises);
Reactor pattern
Quand il est question dâevents-loop on parle souvent de Reactor pattern depuis 1996 (câest le principe qui dĂ©finit les fondamentaux et qui pourra notamment vous permettre de comprendre dâautres pattern de concurrence comme Proactor).
Dans le cadre dâune Event-loop/Reactor on parlera souvent aussi dâalgorithme Round-robin et Demultiplexing dâĂ©vĂšnements.
SchĂ©ma simple dâun Reactor (events loop).
Le rĂ©acteur prend en input un Ă©vĂšnement (lire un fichier, envoyer un paquet sur le rĂ©seau) qui aura un cycle de vie prĂ©dĂ©fini au sein de la loop en fonction de sa nature (et de lâimplĂ©mentation). Les I/O bloquant seront, la plupart du temps, gĂ©rĂ©s au sein dâabstractions bas niveau fournies par le systĂšme comme epoll, kqueue et event ports (tout dĂ©pend du systĂšme dâexploitation cible). Quand il nâest pas possible dâutiliser les ressources du systĂšme, des threads seront bien souvent crĂ©Ă©s.
Une fois le traitement terminĂ© le rĂ©acteur sâoccupera de dĂ©clencher le callback liĂ© Ă lâĂ©vĂšnement pour signaler que le traitement est terminĂ© (avec succĂšs ou en erreur). Je parle ici de callback pour rester bas niveau, mais il peut sâagir dâune Promise/Future ou de toute autre structure ayant pour objectif de gĂ©rer la rĂ©solution dâun Ă©vĂ©nement Asynchrone.
Lien bonus pour les motivés: EN Reactor - An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events
đ„ Un peu dâhistoire
La notion dâevent, event-driven et event-loop ne date pas dâhier et les premiĂšres apparitions date des annĂ©es 80 (mĂȘme si le pattern est devenu fort populaire depuis une dizaine dâannĂ©es grĂące Ă lâapparition de lib comme Libuv ou plus rĂ©cemment Tokio sur Rust).
Il existe trĂšs probablement des librairies Ă©quivalentes ou des implĂ©mentations trĂšs sĂ©rieuses sur les diffĂ©rents runtime (Python, Ruby, PHP, Lua, Perl etc). Le langage de programmation Julia est dâailleurs basĂ© sur Libuv.
Aujourdâhui il devient trĂšs clair que le pattern a fait ses preuves et quâil est trĂšs largement apprĂ©ciĂ© par les dĂ©veloppeurs du monde entier pour construire des programmes concurrents (mĂȘme sâil faut toujours garder en tĂȘte quâil y aura toujours des points forts ainsi que des points faibles).
Il nâest donc ici pas uniquement question de devenir meilleur en Node.js ou en JavaScript, mais dâacquĂ©rir des compĂ©tences et des notions qui vous seront utiles tout au long de votre carriĂšre.
Libuv
Libuv est donc la librairie qui est utilisĂ©e dans Node.js pour lâevent-loop. Son fonctionnement ne vous impacte pas directement dans votre code (elle est transparente pour les dĂ©veloppeurs⊠câest lâobjectif de Node.js ^^).
Il est important de comprendre comment elle fonctionne a minima car lâexĂ©cution des diffĂ©rentes phases va dĂ©finir comment votre code fonctionnera et dans quel ordre il sera exĂ©cutĂ© (ce qui vous permettra de rĂ©soudre le challenge de lâintroduction).
Le schĂ©ma ci-dessous est un schĂ©ma que jâai construit pour reprĂ©senter les diffĂ©rentes phases de lâevent-loop (vous noterez la claire sĂ©paration entre votre code, la loop et le systĂšme dâexploitation).
Sur le sujet je vous recommande dâaller lire en premier lieu les pages suivantes :
- EN [DĂ©butant] The Node.js Event Loop, Timers, and process.nextTick()
- EN [DĂ©butant] Libuv design overview (documentation officielle de Libuv).
- EN [DĂ©butant] An introduction to libuv.
đ Articles et talks
Node.js event-loop par moi (version HD ici).
Divers articles de vulgarisation. Ils peuvent vous permettre de mieux comprendre divers sujets vus plus haut dâune façon plus abordable :
- [DĂ©butant] What you should know to really understand the Node.js Event Loop
- [DĂ©butant] Event Loop and the Big Picture â NodeJS Event Loop Part 1
- [DĂ©butant] Timers, Immediates and Process.nextTickâ NodeJS Event Loop Part 2
- [DĂ©butant] Promises, Next-Ticks, and Immediatesâ NodeJS Event Loop Part 3
- [Débutant] JavaScript Visualized: Event Loop (pas forcément en lien direct avec Node.js)
- FR [DĂ©butant] DĂ©mystifions la boucle dâĂ©vĂ©nement (event loop) de Node.js
- [Intermédiaire] Introduction to Event Loop Utilization in Node.js
Divers talks sur Node.js et libuv (les deux derniers sont en français) :
- EN [DĂ©butant] Everything You Need to Know About Node.js Event Loop
- EN [DĂ©butant] Introduction to libuv: Whatâs a Unicorn Velociraptor?
- EN [DĂ©butant] The Node.js Event Loop: Not So Single Threaded
- EN [A savoir] Node.js Event-Loop: How even quick Node.js async functions can block the Event-Loop, starve I/O
- EN [Intermédiaire] Uncovering Libuv secrets, a practical approach - Santiago Gimeno
- [Intermédiaire] LXJS 2012 - Bert Belder - libuv
- FR [DĂ©butant] Weektalk#1 ES-Community sur lâevent-loop (date un petit peu mais toujours cool).
- FR [DĂ©butant] Apprendre Node.js #5 - Lâevent loop (Vulgarisation de Louistiti).
âŹ ïž đą Node.js: đ° ConfĂ©rences et Articles | âĄïž đą Node.js: đœ Native API (crĂ©ation dâaddon natif en C, C++ et Rust)