Leçon 1 sur 14 · Fondamentaux de Node.js
Node.js : moteur V8, boucle d'événements, versions et REPL
Objectif
Comprendre ce qu'est réellement Node.js et pourquoi il convient si bien aux API (boutique en ligne, réservations, livraison), installer une version LTS avec nvm, et prendre l'habitude de tester des idées dans le REPL et avec de petits scripts.
L'essentiel
- Node.js est un environnement d'exécution JavaScript hors du navigateur : le moteur V8 (celui de Chrome) + la bibliothèque libuv (entrées/sorties asynchrones) + une bibliothèque standard (
node:fs,node:http,node:crypto…). - Un programme Node tourne dans un seul processus et un seul fil JavaScript. Il ne bloque pas pendant une lecture disque ou une requête réseau : il continue et reprend quand la réponse arrive, grâce à la boucle d'événements.
- Conséquence : un serveur Node encaisse des milliers de connexions simultanées… tant que votre code ne fait pas de calcul long et synchrone qui bloque tout le monde.
- En production, utilisez une version LTS (numéro pair : 22, 24…). Les versions impaires ne vivent que quelques mois.
- nvm installe et change de version de Node par utilisateur, sans toucher au système ; un fichier
.nvmrcfixe la version d'un projet. - Le REPL (
nodesans argument),node -eetnode -pservent à essayer une ligne de code en quelques secondes.
Les bases du langage (variables, fonctions, tableaux, promesses) sont traitées dans le cours « Développement web : HTML, CSS et JavaScript ». Ici, nous parlons de ce que Node ajoute autour.
Ce que contient Node.js
votre code JavaScript (serveur.js)
│
┌─────────────────────┴──────────────────────┐
│ bibliothèque standard : node:fs, node:http,│
│ node:path, node:crypto, node:stream… │
├──────────────────────┬──────────────────────┤
│ V8 : compile et │ libuv : boucle │
│ exécute le JS │ d'événements, E/S │
│ (JIT, ramasse- │ asynchrones, pool │
│ miettes) │ de fils pour le │
│ │ disque, DNS, crypto │
└──────────────────────┴──────────────────────┘
système d'exploitation
- V8 transforme votre JavaScript en code machine à la volée (compilation « juste à temps ») et gère la mémoire (ramasse-miettes). C'est pour cela que Node est rapide.
- libuv fournit la boucle d'événements et dialogue avec le système (sockets, fichiers, minuteurs). Certaines opérations lentes (lecture de fichiers, hachage de mot de passe, résolution DNS) partent dans un petit pool de fils caché, puis le résultat revient dans la boucle.
- La bibliothèque standard est riche : on peut écrire un serveur HTTP complet, lire des fichiers, chiffrer, compresser… sans rien installer. Les modules intégrés s'importent avec le préfixe
node:(node:http), recommandé pour éviter toute confusion avec un paquet npm du même nom.
Ce qui change par rapport au navigateur
| Navigateur | Node.js |
|---|---|
window, document, le DOM |
absents : pas de page à afficher |
localStorage |
fichiers (node:fs), bases de données |
| sandbox : pas d'accès disque | accès complet au disque, au réseau, aux processus |
| version de JS imposée par le navigateur du visiteur | vous choisissez la version de Node, donc les fonctionnalités disponibles |
globalThis = window |
globalThis = objet global de Node ; process donne l'environnement |
Ce qui existe des deux côtés : console, setTimeout, fetch, URL, JSON, Promise, structuredClone, crypto.randomUUID()…
Le dernier point du tableau est un vrai avantage : sur le serveur, pas besoin d'attendre que les clients mettent à jour leur navigateur. Si votre projet tourne sous Node 22, toute la syntaxe moderne est disponible.
Le premier programme
mkdir -p ~/essais && cd ~/essais
echo 'console.log("Marhaba depuis Node.js");' > bonjour.js
node bonjour.js # Marhaba depuis Node.js
L'objet process décrit le programme en cours :
// infos.js
console.log(process.version); // 'v22.x.y'
console.log(process.versions.v8); // version du moteur V8 embarqué
console.log(process.platform); // 'linux', 'win32', 'darwin'
console.log(process.argv); // [chemin de node, chemin du script, arguments…]
console.log(process.cwd()); // dossier courant
console.log(process.env.HOME); // variables d'environnement
process.exitCode = 0; // code de sortie (0 = succès)
process.argv contient d'abord le chemin de node, puis celui du script, puis vos arguments, toujours sous forme de texte :
node total.js 120 35.5
# process.argv = ['/usr/bin/node', '/root/total.js', '120', '35.5']
# process.argv.slice(2).map(Number) = [120, 35.5]
La boucle d'événements
Imaginez le serveur d'une application de livraison à Casablanca. Une requête arrive : « liste des commandes du livreur 12 ». Il faut interroger la base, ce qui prend 20 ms. Un serveur « un fil par requête » immobilise un fil pendant ces 20 ms. Node, lui, lance la requête à la base, passe à la requête suivante, et reprend la première quand la base répond.
console.log('A : requête reçue');
setTimeout(() => console.log('C : la base a répondu'), 20); // simule une E/S
console.log('B : je traite déjà la requête suivante');
// A, B, puis C
Le principe :
- Node exécute tout votre script de haut en bas (le code synchrone).
- Les opérations asynchrones (minuteurs, réseau, disque) sont confiées à libuv avec une fonction à rappeler.
- Quand la pile d'appels est vide, la boucle prend les événements terminés et appelle leurs fonctions, une par une.
Même setTimeout(fn, 0) attend donc que le script en cours soit terminé :
console.log('1 debut');
setTimeout(() => console.log('3 minuteur'), 0);
console.log('2 fin du script');
Les phases, en simplifiant
À chaque tour, la boucle passe par des phases dans un ordre fixe :
| Phase | Ce qui s'exécute |
|---|---|
| timers | les setTimeout et setInterval arrivés à échéance |
| poll | les entrées/sorties terminées (réseau, fichiers) ; la boucle peut y attendre |
| check | les setImmediate |
| close | les fermetures (socket.on('close')) |
Entre deux fonctions de rappel, Node vide aussi deux files prioritaires : celle de process.nextTick, puis celle des microtâches (les .then des promesses).
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
Promise.resolve().then(() => console.log('promesse'));
process.nextTick(() => console.log('nextTick'));
console.log('synchrone');
// synchrone, nextTick, promesse, puis timeout et immediate
// (l'ordre de ces deux derniers peut varier dans le script principal)
Vous n'avez pas besoin de retenir chaque phase. Retenez la règle d'or.
La règle d'or : ne bloquez pas la boucle
Il n'y a qu'un seul fil pour votre JavaScript. Un calcul de 2 secondes bloque toutes les requêtes pendant 2 secondes :
import { createServer } from 'node:http';
createServer((req, res) => {
if (req.url === '/rapport') {
const fin = Date.now() + 2000;
while (Date.now() < fin) {} // MAUVAIS : 2 s de calcul synchrone
}
res.end('ok\n');
}).listen(3000);
// pendant qu'un client demande /rapport, les autres attendent, même pour '/'
À éviter dans un serveur :
- les fonctions synchrones d'entrées/sorties (
fs.readFileSync,crypto.pbkdf2Sync…) dans le traitement d'une requête : réservez-les au démarrage ; - les grosses boucles sur des millions d'éléments, les
JSON.parsede fichiers énormes ; - les expressions régulières mal écrites sur des textes fournis par l'utilisateur.
L'option node --trace-sync-io serveur.js affiche un avertissement chaque fois qu'une API synchrone est appelée après le démarrage : pratique pour traquer les blocages avant la production. Pour les vrais calculs lourds (génération de PDF, traitement d'images), on utilise des worker_threads ou un service à part.
Les versions de Node.js
Une nouvelle version majeure sort tous les six mois :
- en avril : version paire (22, 24, 26…) ; elle devient LTS (Long Term Support) en octobre ;
- en octobre : version impaire (23, 25…), maintenue environ six mois seulement, pour essayer les nouveautés.
Une version LTS passe par trois états :
| État | Durée approximative | Ce qu'elle reçoit |
|---|---|---|
| Current | 6 mois | toutes les nouveautés |
| Active LTS | 12 mois | correctifs, améliorations prudentes |
| Maintenance LTS | 18 mois | correctifs de sécurité et bugs critiques |
Soit environ 30 mois de vie. Situation à la date de ce cours (octobre 2026) :
| Version | État | Fin de vie |
|---|---|---|
| Node 20 | fin de vie | avril 2026 : à migrer |
| Node 22 | Maintenance LTS | avril 2027 |
| Node 24 | Active LTS | avril 2028 |
| Node 26 | Current, LTS fin octobre 2026 | avril 2029 |
Vérifiez toujours le calendrier officiel sur le site de Node.js avant de choisir : les dates exactes y sont publiées et le rythme peut évoluer. Le lab de ce cours utilise Node 22.
En pratique, pour une API en production : la LTS active la plus récente, ou la précédente si une bibliothèque n'est pas encore compatible. Jamais une version impaire. Express 5, par exemple, exige au minimum Node 18.
Installer Node.js
Avec nvm (recommandé en développement)
nvm (Node Version Manager) installe Node dans votre dossier personnel. Plusieurs versions cohabitent, sans sudo.
# installation de nvm (script officiel du projet nvm-sh/nvm sur GitHub ;
# vérifiez la dernière version sur la page du projet)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.bashrc # recharger le shell
nvm install --lts # dernière LTS
nvm install 22 # une branche précise
nvm ls # versions installées
nvm use 22 # utiliser Node 22 dans ce terminal
nvm alias default 22 # version par défaut des nouveaux terminaux
node --version && npm --version
Dans chaque projet, un fichier .nvmrc fixe la version attendue :
echo 22 > .nvmrc
nvm use # lit .nvmrc : toute l'équipe a la même version
Sous Windows, utilisez nvm-windows ou fnm, ou l'installateur officiel de nodejs.org.
Sur un serveur
- Les paquets de la distribution (
apt install nodejs) sont souvent anciens : vérifiez la version avant de vous y fier. - Les dépôts NodeSource fournissent des paquets
.deb/.rpmpar branche LTS, mis à jour parapt upgrade. - En conteneur, partez de l'image officielle
node:22-slimounode:22-alpine(cours Docker).
Le REPL et les commandes rapides
Lancé sans argument, node ouvre le REPL (Read-Eval-Print Loop) : il lit une expression, l'évalue, affiche le résultat et recommence.
$ node
Welcome to Node.js v22.x.y.
> 120 * 1.2
144
> _ + 10 // _ = le dernier résultat
154
> const tva = 0.2
undefined
> [100, 250].map(p => p * (1 + tva))
[ 120, 300 ]
> 0.1 + 0.2
0.30000000000000004 // les prix en dirhams se calculent en centimes entiers !
> .help // commandes du REPL
> .editor // saisir plusieurs lignes, Ctrl+D pour exécuter
> .exit // ou Ctrl+D
La touche Tab complète les noms : tapez fs. puis Tab pour voir les fonctions du module fs, chargé d'office dans le REPL.
Sans ouvrir de REPL :
node -e 'console.log(new Date().toISOString())' # exécuter une ligne
node -p '1500 * 0.2' # exécuter ET afficher le résultat : 300
node -p 'process.versions' # versions de V8, libuv, OpenSSL…
node --check serveur.js # vérifier la syntaxe sans exécuter
node --watch serveur.js # relancer à chaque modification (développement)
Pièges fréquents
- Bloquer la boucle d'événements avec un calcul long ou une fonction
…Syncdans une requête : tout le serveur se fige, pour tous les clients. - Utiliser une version impaire ou en fin de vie en production : plus de correctifs de sécurité. Suivez la LTS.
- Installer Node avec
sudo aptsans vérifier la version : vous pouvez récupérer une branche dépassée. Vérifiez avecnode --version. - Oublier que
process.argvcontient du texte :'120' + '35'donne'12035'. Convertissez avecNumber().
Lab
Dans le lab (Node 22, sans réseau), vous allez :
- écrire et lancer un premier script ;
- relever la version de Node installée ;
- lire des arguments de la ligne de commande pour calculer un total en dirhams ;
- vérifier par vous-même l'ordre d'exécution imposé par la boucle d'événements.
Pour créer un fichier sans éditeur, utilisez echo '…' > fichier ou cat > fichier <<'EOF' … EOF.
Quiz
- Quels sont les trois grands composants de Node.js ?
- Pourquoi un serveur Node peut-il gérer des milliers de connexions avec un seul fil ?
- Dans quel ordre s'affichent
console.log('a'),setTimeout(() => console.log('b'), 0)etconsole.log('c')écrits dans cet ordre ? - Vous démarrez une API pour un riad en octobre 2026 : Node 25 ou Node 24 ? Pourquoi ?
- À quoi sert le fichier
.nvmrc?
Réponses
- Le moteur V8 (exécution du JavaScript), libuv (boucle d'événements et entrées/sorties asynchrones) et la bibliothèque standard (
node:fs,node:http…). - Parce que les entrées/sorties ne bloquent pas : Node les confie au système, traite d'autres requêtes, puis reprend chaque traitement quand le résultat arrive (boucle d'événements).
a,c, puisb: le minuteur ne s'exécute qu'une fois le script synchrone terminé.- Node 24 : c'est une version paire LTS, maintenue jusqu'en 2028. Node 25 est impaire, sans support long.
- À fixer la version de Node d'un projet :
nvm usela lit, et toute l'équipe travaille avec la même version.
Sources de référence : documentation officielle de Node.js (nodejs.org, licence MIT) et d'Express (expressjs.com, CC BY-SA 3.0). Texte original MasterLinux.