Node.js est une plateforme logicielle libre en JavaScript, orientée vers les applications réseau évènementielles hautement concurrentes qui doivent pouvoir monter en charge.
Elle utilise la machine virtuelle V8, la librairie libuv pour sa boucle d'évènements, et implémente sous licence MIT les spécifications CommonJS.
Parmi les modules natifs de Node.js, on retrouve http qui permet le développement de serveur HTTP. Ce qui autorise, lors du déploiement de sites internet et d'applications web développés avec Node.js, de ne pas installer et utiliser des serveurs webs tels que Nginx ou Apache.
Concrètement, Node.js est un environnement bas niveau permettant l’exécution de JavaScript côté serveur.
Node.js est utilisé notamment comme plateforme de serveur Web, elle est utilisée par GoDaddy, IBM, Netflix, Amazon Web Services, Groupon, Vivaldi, SAP, LinkedIn, Microsoft, Yahoo!, Walmart, Rakuten, Sage et PayPal.
Installation
Installation pour Windows 16.15.0 LTSTélécharger NodeJS 16.15.0 LTS .msi (32-bit)
Télécharger NodeJS 16.15.0 LTS .msi (64-bit)
Télécharger NodeJS 16.15.0 LTS .zip (32-bit)
Télécharger NodeJS 16.15.0 LTS .zip (64-bit)
Installation pour Windows 18.2.0 CurrentTélécharger NodeJS 18.2.0 Current .msi (32-bit)
Télécharger NodeJS 18.2.0 Current .msi (64-bit)
Télécharger NodeJS 18.2.0 Current .zip (32-bit)
Télécharger NodeJS 18.2.0 Current .zip (64-bit)
Source Rust
nodejs.orgnodejs.org docs v16.15.0 LTS FR
nodejs.org docs v18.2.0 Current FR
A propos de Node.js
En tant qu'environnement d'exécution JavaScript asynchrone et orienté événement, Node.js est conçu pour générer des applications extensibles. Dans cet exemple ("hello world"), plusieures connexions peuvent être gérées de manière concurrente. À chaque connexion, la fonction de rappel (callback function) est déclenchée, mais si il n'y a rien à faire, Node.js restera inactif.
const http = require('http');const hostname = '127.0.0.1';const port = 3000;const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World');});server.listen(port, hostname, () => {console.log(`Server running at http://${hostname}:${port}/`);});
Ceci contraste avec le modèle de concurrence plus commun dans lequel les processus sytème sont utilisés. La gestion réseau basée sur les processus est relativement inefficace et difficile à utiliser. De plus, les utilisateurs de Node.js n'ont pas à se soucier des problèmes d'interblocage des processus puisqu'il n'y a pas de verrouillage. Aucune fonction de Node.js ou presque n'effectue d'entrée/sortie, donc le processus ne se bloque pas. Et comme rien n'est bloquant, développer un système extensible est relativement aisé avec Node.js.
Si une partie des termes utilisés ne vous sont pas familliers, voici un article complet (en anglais) Bloquant vs Non-Bloquant.
voici un article complet (en FR) Bloquant vs Non-Bloquant
Node.js est conçu de manière similaire et influencé par des librairies comme Event Machine (en) pour Ruby et Twisted (en) pour Python. Node.js pousse le modèle événementiel encore plus loin. Il instaure la boucle événementielle (en) en tant que composant élémentaire de l'environnement d'exécution et non comme une librairie. Dans les autres systèmes, il y a toujours un appel bloquant pour démarrer la boucle événementielle. Le comportement est défini habituellement par des fonctions de rappel au début du script, et à la fin un serveur est démarré avec un appel bloquant comme EventMachine::run(). Dans Node.js, il n'y a pas d'appel pour démarrer la boucle. Node.js entre simplement dans la boucle après avoir exécuté le script d'entrée. Node.js sort de la boucle événementielle lorsqu'il n'y a plus de fonction de rappel à exécuter. Ce comportement est similaire à celui de JavaScript dans un navigateur - la boucle événementielle est cachée à l'utilisateur.
HTTP a une place prépondérante dans Node.js, qui a été conçu pour le streaming et une faible latence. Ceci fait de Node.js une base toute désignée pour une librairie web ou un framework.
Et si Node.js a été conçu sans processus multiples, vous pouvez tout de même profiter d'un environnement multi-coeur. Vous pouvez générer des processus enfant par le biais de l'API [child_process.fork()][] (en), avec lesquels vous pourrez communiquer facilement. Basé sur la même interface, le module [cluster][] (en) vous permettra de partager les sockets entre vos processus pour faire de la répartition de charge entre vos coeurs.
Documentation NodeJS
nodejs.org docs api 16.15.0nodejs.org docs api 18.2.0
Vidéo NodeJS FR
NodeJS (1/6) : Qu'est ce que NodeJS ?
NodeJS (2/6) : Installation
NodeJS (3/6) : Notre premier serveur
NodeJS (4/6) : Les Streams
NodeJS (5/6) : Modules & NPM
NodeJS (6/6) : ExpressJS
Node JS Tutorial Français pour Débutant - Cours complet 8h [2022]
Présentation du Bloquant et du Non-Bloquant
Cet aperçu couvre la différence entre les appels bloquants et non bloquants dans Node.js. Cet aperçu fera référence à la boucle d'événements et à libuv, mais aucune connaissance préalable de ces sujets n'est requise. Les lecteurs sont supposés avoir une compréhension de base du langage JavaScript et Node.js callback pattern.
"I/O" se réfère principalement à l'interaction avec le disque et le réseau du système pris en charge par libuv.
Blocage
Le blocage se produit lorsque l'exécution de JavaScript supplémentaire dans le processus Node.js doit attendre qu'une opération non JavaScript se termine. Cela se produit car la boucle d'événements ne peut pas continuer à exécuter JavaScript pendant qu'une opération de blocage est en cours.
Dans Node.js, JavaScript qui présente des performances médiocres en raison d'une utilisation intensive du processeur plutôt que d'attendre une opération non JavaScript, telle qu'une I/O, n'est généralement pas appelé blocage. Les méthodes synchrones de la bibliothèque standard Node.js qui utilisent libuv sont les opérations de blocage les plus couramment utilisées. Les modules natifs peuvent également avoir des méthodes de blocage.
Toutes les méthodes d'I/O de la bibliothèque standard Node.js fournissent des versions asynchrones, non bloquantes, et acceptent les fonctions de rappel. Certaines méthodes ont également des homologues bloquants, dont les noms se terminent par Sync.
Code de comparaison
Les méthodes bloquantes s'exécutent de manière synchrone et les méthodes non bloquantes s'exécutent de manière asynchrone.
En utilisant le module File System comme exemple, il s'agit d'une lecture de fichier synchrone :
const fs = require('fs');données const = fs.readFileSync('/file.md');// bloque ici jusqu'à ce que le fichier soit lu
Et voici un exemple asynchrone équivalent :
const fs = require('fs');fs.readFile('/file.md', (err, data) => { if (err) throw err;});
Le premier exemple semble plus simple que le second mais présente l'inconvénient que la seconde ligne bloque l'exécution de tout JavaScript supplémentaire jusqu'à ce que le fichier entier soit lu. Notez que dans la version synchrone, si une erreur est renvoyée, elle devra être interceptée ou le processus plantera. Dans la version asynchrone, c'est à l'auteur de décider si une erreur doit être renvoyée comme indiqué.
Développons un peu notre exemple :
const fs = require('fs');données const = fs.readFileSync('/file.md');// bloque ici jusqu'à ce que le fichier soit luconsole.log(data);moreWork(); // s'exécutera après console.log
Et voici un exemple asynchrone similaire, mais non équivalent :
const fs = require('fs');fs.readFile('/file.md', (err, data) => { if (err) throw err; console.log(data);
});moreWork(); // s'exécutera avant console.log
Dans le premier exemple ci-dessus, console.log sera appelé avant moreWork(). Dans le deuxième exemple, fs.readFile() est non bloquant, l'exécution de JavaScript peut donc continuer et moreWork() sera appelé en premier. La possibilité d'exécuter moreWork() sans attendre la fin de la lecture du fichier est un choix de conception clé qui permet un débit plus élevé.
Concurrence et débit
L'exécution de JavaScript dans Node.js est monothread, donc la simultanéité fait référence à la capacité de la boucle d'événements à exécuter des fonctions de rappel JavaScript après avoir terminé d'autres travaux. Tout code censé s'exécuter de manière simultanée doit permettre à la boucle d'événements de continuer à s'exécuter pendant que des opérations non JavaScript, telles que des I/O, se produisent.
À titre d'exemple, considérons un cas où chaque demande à un serveur Web prend 50 ms pour se terminer et 45 ms de ces 50 ms sont des I/O de base de données qui peuvent être effectuées de manière asynchrone. Le choix d'opérations asynchrones non bloquantes libère ces 45 ms par requête pour gérer d'autres requêtes. Il s'agit d'une différence de capacité significative simplement en choisissant d'utiliser des méthodes non bloquantes au lieu de méthodes bloquantes.
La boucle d'événements est différente des modèles dans de nombreux autres langages où des threads supplémentaires peuvent être créés pour gérer le travail simultané.
Dangers du mélange de codes bloquants et non bloquants
Certains schémas doivent être évités lorsqu'il s'agit d'I/O. Regardons un exemple :
const fs = require('fs');fs.readFile('/file.md', (err, data) => { if (err) throw err; console.log(data);});fs.unlinkSync('/file.md');
Dans l'exemple ci-dessus, fs.unlinkSync() est susceptible d'être exécuté avant fs.readFile(), ce qui supprimerait file.md avant qu'il ne soit réellement lu. Une meilleure façon d'écrire ceci, qui est complètement non bloquant et garanti pour s'exécuter dans le bon ordre est :
const fs = require('fs');
fs.readFile('/file.md', (readFileErr, données) => { if (readFileErr) throw readFileErr; console.log(data); fs.unlink('/fichier.md', (unlinkErr) => { if (unlinkErr) throw unlinkErr; });});
Ce qui précède place un appel non bloquant à fs.unlink() dans le rappel de fs.readFile() qui garantit le bon ordre des opérations.
Présentation Callbacks
Dans un programme synchrone, vous écririez quelque chose comme :
function processData () { var data = fetchData (); data += 1; return data;}
Cela fonctionne très bien et est très typique dans d'autres environnements de développement. Cependant, si fetchData prend beaucoup de temps pour charger les données (peut-être qu'il les diffuse depuis le lecteur ou Internet), cela provoque le "blocage" de l'ensemble du programme - autrement connu sous le nom de rester immobile et d'attendre - jusqu'à ce qu'il charge les données . Node.js, étant une plate-forme asynchrone, n'attend pas que des choses comme les I/O de fichiers se terminent - Node.js utilise des rappels. Un rappel est une fonction appelée à la fin d'une tâche donnée ; cela empêche tout blocage et permet à d'autres codes d'être exécutés entre-temps.
La façon dont Node.js traite ce qui précède ressemblerait un peu plus à ceci :
function processData (callback) { fetchData(function (err, data) { if (err) { console.log("An error has occurred. Abort everything!"); return callback(err); } data += 1; callback(data); });}
À première vue, cela peut sembler inutilement compliqué, mais les rappels sont à la base de Node.js. Les rappels vous donnent une interface avec laquelle dire "et quand vous avez fini de faire ça, faites tout ça". Cela vous permet d'avoir autant d'opérations d'I/O que votre système d'exploitation peut gérer en même temps. Par exemple, dans un serveur Web avec des centaines ou des milliers de requêtes en attente avec plusieurs requêtes bloquantes, l'exécution des requêtes bloquantes de manière asynchrone vous permet de continuer à travailler et pas simplement de rester immobile et d'attendre que les opérations de blocage reviennent. C'est une amélioration majeure.
La convention typique avec les fonctions asynchrones (ce que presque toutes vos fonctions devraient être) :
function asyncOperation ( a, b, c, callback ) { // ... lots of hard work ... if ( /* an error occurs */ ) { return callback(new Error("An error has occurred")); } // ... more work ... callback(null, d, e, f);}asyncOperation ( params.., function ( err, returnValues.. ) { //This code gets run after the async operation gets run});
Actualités NodeJS
nodejs.org docs blogVous voudrez presque toujours suivre la convention de rappel d'erreur, car la plupart des utilisateurs de Node.js s'attendront à ce que votre projet les suive. L'idée générale est que le rappel est le dernier paramètre. Le rappel est appelé une fois que la fonction a terminé toutes ses opérations. Traditionnellement, le premier paramètre du rappel est la valeur d'erreur. Si la fonction rencontre une erreur, elle appelle généralement le rappel avec le premier paramètre étant un objet Error. S'il se termine proprement, ils appelleront le rappel avec le premier paramètre étant nul et le reste étant la ou les valeurs de retour.