Qu'est-ce que Node.js? Le runtime JavaScript expliqué

L'évolutivité, la latence et le débit sont des indicateurs de performance clés pour les serveurs Web. Il n'est pas facile de maintenir une latence faible et un débit élevé tout en augmentant et en sortant. Node.js est un environnement d'exécution JavaScript qui atteint une faible latence et un débit élevé en adoptant une approche «non bloquante» pour traiter les demandes. En d'autres termes, Node.js ne perd pas de temps ni de ressources à attendre le retour des demandes d'E / S.

Dans l'approche traditionnelle de la création de serveurs Web, pour chaque demande ou connexion entrante, le serveur génère un nouveau thread d'exécution ou même crée un nouveau processus pour gérer la demande et envoyer une réponse. Conceptuellement, cela est parfaitement logique, mais dans la pratique, cela entraîne beaucoup de frais généraux.

Bien que la génération de threads entraîne moins de frais de mémoire et de processeur que les processus de fourche , elle peut toujours être inefficace. La présence d'un grand nombre de threads peut amener un système fortement chargé à consacrer de précieux cycles à la planification des threads et au changement de contexte, ce qui ajoute de la latence et impose des limites d'évolutivité et de débit.

Node.js adopte une approche différente. Il exécute une boucle d'événements à thread unique enregistrée auprès du système pour gérer les connexions, et chaque nouvelle connexion provoque le déclenchement d'une fonction de rappel JavaScript . La fonction de rappel peut gérer les demandes avec des appels d'E / S non bloquants et, si nécessaire, générer des threads à partir d'un pool pour exécuter des opérations de blocage ou gourmandes en ressources processeur et pour équilibrer la charge sur les cœurs de processeur. L'approche de Node en matière de mise à l'échelle avec des fonctions de rappel nécessite moins de mémoire pour gérer plus de connexions que la plupart des architectures concurrentes qui évoluent avec des threads, y compris Apache HTTP Server, les divers serveurs d'applications Java, IIS et ASP.NET, et Ruby on Rails.

Node.js s'avère très utile pour les applications de bureau en plus des serveurs. Notez également que les applications Node ne sont pas limitées au JavaScript pur. Vous pouvez utiliser n'importe quel langage qui transpile en JavaScript, par exemple TypeScript et CoffeeScript. Node.js intègre le moteur JavaScript Google Chrome V8, qui prend en charge la syntaxe ECMAScript 2015 (ES6) sans avoir besoin d'un transpilateur ES6 vers ES5 tel que Babel.

Une grande partie de l'utilitaire de Node provient de sa grande bibliothèque de packages, accessible à partir de la npmcommande. NPM, le gestionnaire de packages Node, fait partie de l'installation standard de Node.js, bien qu'il dispose de son propre site Web.

Un peu d'histoire JavaScript

En 1995, Brendan Eich, alors sous-traitant de Netscape, a créé le langage JavaScript pour fonctionner dans les navigateurs Web - en 10 jours, selon le récit. JavaScript était initialement destiné à permettre des animations et d'autres manipulations du modèle d'objet de document (DOM) du navigateur. Une version de JavaScript pour Netscape Enterprise Server a été introduite peu de temps après.

Le nom JavaScript a été choisi à des fins de marketing, car le langage Java de Sun était très populaire à l'époque. En fait, le langage JavaScript était en fait basé principalement sur les langages Scheme et Self, avec une sémantique superficielle de type Java.

Au départ, de nombreux programmeurs ont rejeté JavaScript comme inutile pour le «vrai travail» parce que son interpréteur exécutait un ordre de grandeur plus lent que les langages compilés. Cela a changé lorsque plusieurs efforts de recherche visant à rendre JavaScript plus rapide ont commencé à porter leurs fruits. Plus important encore, le moteur JavaScript open-source Google Chrome V8, qui effectue la compilation juste à temps, l'intégration et l'optimisation du code dynamique, peut en fait surpasser le code C ++ pour certaines charges et surpasser Python pour la plupart des cas d'utilisation.

La plate-forme Node.js basée sur JavaScript a été introduite en 2009, par Ryan Dahl, pour Linux et MacOS, comme une alternative plus évolutive au serveur HTTP Apache. NPM, écrit par Isaac Schlueter, a été lancé en 2010. Une version Windows native de Node.js a fait ses débuts en 2011.

Joyent a possédé, gouverné et soutenu l'effort de développement de Node.js pendant de nombreuses années. En 2015, le projet Node.js a été transféré à la Fondation Node.js, et est devenu régi par le comité de pilotage technique de la fondation. Node.js a également été adopté en tant que projet collaboratif de la Fondation Linux. En 2019, la Fondation Node.js et la Fondation JS ont fusionné pour former la Fondation OpenJS.

Architecture de base de Node.js

À un niveau élevé, Node.js combine le moteur JavaScript de Google V8, une boucle d'événements non bloquants à un seul thread et une API d'E / S de bas niveau. L'exemple de code dépouillé ci-dessous illustre le modèle de serveur HTTP de base, à l'aide des fonctions fléchées ES6 (fonctions Lambda anonymes déclarées à l'aide de l'opérateur de grosse flèche =>) pour les rappels.

Le début du code charge le module HTTP, définit la hostnamevariable de serveur sur localhost(127.0.0.1) et définit la portvariable sur 3000. Ensuite, il crée un serveur et une fonction de rappel, dans ce cas une fonction de grosse flèche qui renvoie toujours la même réponse à toute demande: statusCode200 (succès), type de contenu texte brut et une réponse textuelle de ”Hello World\n”. Enfin, il indique au serveur d'écouter sur le localhostport 3000 (via une socket) et définit un rappel pour imprimer un message de journal sur la console lorsque le serveur a commencé à écouter. Si vous exécutez ce code dans un terminal ou une console à l'aide de la nodecommande, puis accédez à localhost: 3000 à l'aide de n'importe quel navigateur Web sur la même machine, vous verrez «Hello World» dans votre navigateur. Pour arrêter le serveur, appuyez sur Ctrl-C dans la fenêtre du terminal.

Notez que chaque appel effectué dans cet exemple est asynchrone et non bloquant. Les fonctions de rappel sont appelées en réponse à des événements. Le createServerrappel gère un événement de demande client et renvoie une réponse. Le listenrappel gère l' listeningévénement.

La bibliothèque Node.js

Comme vous pouvez le voir sur le côté gauche de la figure ci-dessous, Node.js a une large gamme de fonctionnalités dans sa bibliothèque. Le module HTTP que nous avons utilisé dans l'exemple de code précédemment contient à la fois des classes client et serveur, comme vous pouvez le voir sur le côté droit de la figure. La fonctionnalité de serveur HTTPS utilisant TLS ou SSL réside dans un module séparé.

Un problème inhérent à une boucle d'événements à un seul thread est un manque de mise à l'échelle verticale, car le thread de la boucle d'événements n'utilisera qu'un seul cœur de processeur. Pendant ce temps, les puces de processeur modernes exposent souvent huit cœurs ou plus, et les racks de serveurs modernes ont souvent plusieurs puces de processeur. Une application à un seul thread ne profitera pas pleinement des 24 cœurs et plus d'un rack de serveurs robuste.

Vous pouvez résoudre ce problème, même si cela nécessite une programmation supplémentaire. Pour commencer, Node.js peut engendrer des processus enfants et maintenir des canaux entre le parent et les enfants, de la même manière que l' popen(3)appel système fonctionne, en utilisant child_process.spawn() et des méthodes associées.

Le module de cluster est encore plus intéressant que le module de processus enfant pour créer des serveurs évolutifs. La cluster.fork()méthode génère des processus de travail qui partagent les ports du serveur parent, en utilisant child_process.spawn()sous les couvertures. Le maître de cluster distribue les connexions entrantes entre ses nœuds de calcul à l'aide, par défaut, d'un algorithme de répétition alternée sensible aux charges de processus de travail.

Notez que Node.js ne fournit pas de logique de routage. Si vous souhaitez conserver l'état des connexions dans un cluster, vous devez conserver votre session et vos objets de connexion ailleurs que dans la RAM de travail.

L'écosystème de packages Node.js

Le registre NPM héberge plus de 1,2 million de packages de code Node.js gratuit et réutilisable, ce qui en fait le plus grand registre de logiciels au monde. Notez que la plupart des packages NPM (essentiellement des dossiers ou des éléments de registre NPM contenant un programme décrit par un fichier package.json) contiennent plusieurs modules (programmes que vous chargez avec des requireinstructions). Il est facile de confondre les deux termes, mais dans ce contexte, ils ont des significations spécifiques et ne doivent pas être interchangés.

NPM peut gérer des packages qui sont des dépendances locales d'un projet particulier, ainsi que des outils JavaScript installés globalement. Lorsqu'il est utilisé comme gestionnaire de dépendances pour un projet local, NPM peut installer, en une seule commande, toutes les dépendances d'un projet via le fichier package.json. Lorsqu'il est utilisé pour des installations globales, NPM nécessite souvent des privilèges système (sudo).

Vous n'avez pas besoin d'utiliser la ligne de commande NPM pour accéder au registre NPM public. D'autres gestionnaires de packages tels que Facebook's Yarn proposent des expériences alternatives côté client. Vous pouvez également rechercher et parcourir les packages à l'aide du site Web NPM.

Pourquoi voudriez-vous utiliser un package NPM? Dans de nombreux cas, l'installation d'un package via la ligne de commande NPM est la méthode la plus rapide et la plus pratique pour obtenir la dernière version stable d'un module en cours d'exécution dans votre environnement, et représente généralement moins de travail que le clonage du référentiel source et la création d'une installation à partir du référentiel. Si vous ne voulez pas la dernière version, vous pouvez spécifier un numéro de version à NPM, ce qui est particulièrement utile lorsqu'un package dépend d'un autre package et peut rompre avec une version plus récente de la dépendance.

Par exemple, le framework Express, un framework d'application Web Node.js minimal et flexible, fournit un ensemble robuste de fonctionnalités pour la création d'applications Web hybrides et monopages. Alors que le référentiel Expresscode facilement clonable réside sur //github.com/expressjs/express et que la documentation Express est sur //expressjs.com/, un moyen rapide de commencer à utiliser Express consiste à l'installer dans un développement de travail local déjà initialisé. répertoire avec la npmcommande, par exemple:

$ npm install express - enregistrer

L' —saveoption, qui est en fait activée par défaut dans NPM 5.0 et versions ultérieures, indique au gestionnaire de packages d'ajouter le module Express à la liste des dépendances dans le fichier package.json après l'installation.

Un autre moyen rapide de commencer à utiliser Express est d'installer le générateur exécutable express(1) globalement, puis de l'utiliser pour créer l'application localement dans un nouveau dossier de travail:

$ npm install -g générateur-express @ 4

$ express / tmp / foo && cd / tmp / foo

Une fois cela fait, vous pouvez utiliser NPM pour installer toutes les dépendances nécessaires et démarrer le serveur, en fonction du contenu du fichier package.json créé par le générateur:

Installation de $ npm

$ npm début

Il est difficile de choisir des points forts parmi les millions de packages du NPM, mais quelques catégories se démarquent. Express est l'exemple le plus ancien et le plus important de frameworks Node.js. Les utilitaires de développement JavaScript, notamment browserify, un bundler de modules, constituent une autre grande catégorie du référentiel NPM; bower, le gestionnaire de packages du navigateur; grunt, le lanceur de tâches JavaScript; et gulp, le système de construction de streaming. Enfin, une catégorie importante pour les développeurs Node.js d'entreprise est constituée par les clients de base de données, qui sont plus de 8 000, y compris des modules populaires tels que redis, mongoose, firebase et pg, le client PostgreSQL.

Pour résumer, Node.js est un environnement d'exécution JavaScript multiplateforme pour les serveurs et les applications. Il repose sur une boucle d'événement non bloquante à thread unique, le moteur JavaScript Google Chrome V8 et une API d'E / S de bas niveau. Diverses techniques, y compris le module de cluster, permettent aux applications Node.js d'évoluer au-delà d'un seul cœur de processeur. Au-delà de sa fonctionnalité de base, Node.js a inspiré un écosystème de plus d'un million de packages qui sont enregistrés et versionnés dans le référentiel NPM et peuvent être installés à l'aide de la ligne de commande NPM ou d'une alternative telle que Yarn.