035.1 Leçon 1
Certification : |
Web Development Essentials |
---|---|
Version : |
1.0 |
Thème : |
035 Programmation de serveur NodeJS |
Objectif : |
035.1 Bases de NodeJS |
Leçon : |
1 sur 1 |
Introduction
Node.js est un environnement d’exécution JavaScript qui exécute du code JavaScript dans les serveurs Web - ce que l’on appelle le backend web (côté serveur) - au lieu d’utiliser un deuxième langage comme Python ou Ruby pour les programmes côté serveur. Le langage JavaScript est déjà utilisé dans le côté frontal moderne des applications web, interagissant avec le HTML et le CSS de l’interface avec laquelle l’utilisateur interagit dans un navigateur web. L’utilisation de Node.js en tandem avec JavaScript dans le navigateur offre la possibilité d’utiliser un seul langage de programmation pour l’ensemble de l’application.
La principale raison de l’existence de Node.js est la façon dont il gère les connexions multiples et simultanées dans le backend. L’une des façons les plus courantes dont un serveur d’applications web gère les connexions est l’exécution de plusieurs processus. Lorsque vous ouvrez une application de bureau sur votre ordinateur, un processus démarre et utilise beaucoup de ressources. Imaginez maintenant que des milliers d’utilisateurs fassent la même chose dans une grande application web.
Node.js évite ce problème en utilisant une conception appelée la boucle d’événement (event loop en anglais), qui est une boucle interne qui vérifie continuellement les tâches entrantes à calculer. Grâce à l’utilisation répandue de JavaScript et à l’omniprésence des technologies web, Node.js a connu une adoption massive dans les petites et grandes applications. D’autres caractéristiques ont également contribué à la large adoption de Node.js, comme le traitement asynchrone et non bloquant des entrées/sorties (E/S), qui est expliqué plus loin dans cette leçon.
L’environnement Node.js utilise un moteur JavaScript pour interpréter et exécuter le code JavaScript du côté serveur ou sur le bureau. Dans ces conditions, le code JavaScript que le programmeur écrit est analysé et compilé juste à temps pour exécuter les instructions machine générées par le code JavaScript original.
Note
|
Au fur et à mesure que vous progresserez dans ces leçons sur Node.js, vous remarquerez peut-être que le JavaScript de Node.js n’est pas exactement le même que celui qui s’exécute sur le navigateur (qui suit la spécification ECMAScript), mais qu’il est assez similaire. |
Pour commencer
Cette section et les exemples suivants supposent que Node.js est déjà installé sur votre système d’exploitation Linux, et que l’utilisateur possède déjà des compétences de base telles que l’exécution de commandes dans le terminal.
Pour exécuter les exemples suivants, créez un répertoire de travail appelé node_examples
. Ouvrez un terminal et tapez node
. Si vous avez correctement installé Node.js, il présentera une invite >
où vous pourrez tester les commandes JavaScript de manière interactive. Ce type d’environnement est appelé REPL, pour “read, evaluate, print, and loop” (en français : “lire, évaluer, afficher et boucler”). Tapez les entrées suivantes (ou d’autres instructions JavaScript) à l’invite >
. Appuyez sur la touche Entrée après chaque ligne, et l’environnement REPL vous renverra les résultats de ses actions :
> let array = ['a', 'b', 'c', 'd']; undefined > array.map( (element, index) => (`Element: ${element} at index: ${index}`)); [ 'Element: a at index: 0', 'Element: b at index: 1', 'Element: c at index: 2', 'Element: d at index: 3' ] >
L’extrait a été écrit en utilisant la syntaxe ES6, qui propose une fonction map
pour itérer sur le tableau et afficher les résultats à l’aide de modèles de chaîne. Vous pouvez écrire à peu près n’importe quelle commande qui soit valide. Pour quitter le terminal Node.js, tapez .exit
, en n’oubliant pas d’inclure le point initial.
Pour les scripts et modules plus longs, il est plus pratique d’utiliser un éditeur de texte tel que VS Code, Emacs ou Vim. Vous pouvez enregistrer les deux lignes de code que vous venez de voir (avec une petite modification) dans un fichier appelé start.js
:
let array = ['a', 'b', 'c', 'd'];
array.map( (element, index) => ( console.log(`Element: ${element} at index: ${index}`)));
Vous pouvez ensuite exécuter le script à partir du Shell pour obtenir les mêmes résultats que précédemment :
$ node ./start.js Element: a at index: 0 Element: b at index: 1 Element: c at index: 2 Element: d at index: 3
Avant de plonger dans un peu plus de code, nous allons avoir un aperçu du fonctionnement de Node.js, en utilisant son environnement d’exécution à fil unique et la boucle d’événement.
Boucle d’événement et fil unique
Il est difficile de dire combien de temps votre programme Node.js prendra pour traiter une requête. Certaines requêtes peuvent être courtes - peut-être simplement en bouclant sur des variables en mémoire et en les retournant - alors que d’autres peuvent nécessiter des activités longues comme l’ouverture d’un fichier sur le système ou l’envoi d’une requête à une base de données et l’attente des résultats. Comment Node.js gère-t-il cette incertitude ? La réponse est la boucle d’événement.
Imaginez un chef cuisinier effectuant plusieurs tâches. La cuisson d’un gâteau est une tâche qui nécessite beaucoup de temps pour que le four le prépare. Le chef ne reste pas là à attendre que le gâteau soit prêt pour ensuite aller faire du café. Au contraire, pendant que le four cuit le gâteau, le chef prépare le café et d’autres tâches en parallèle. Mais le cuisinier vérifie toujours si c’est le bon moment pour se concentrer sur une tâche spécifique (faire du café) ou pour sortir le gâteau du four.
La boucle d’événement est comme le chef qui est constamment au courant des activités environnantes. Dans Node.js, un “event-checker” vérifie en permanence les opérations qui se sont terminées ou qui attendent d’être traitées par le moteur JavaScript.
Grâce à cette approche, une opération longue et asynchrone ne bloque pas les autres opérations rapides qui suivent. En effet, le mécanisme de boucle d’événement vérifie toujours si cette longue tâche, telle qu’une opération d’E/S, est déjà terminée. Si ce n’est pas le cas, Node.js peut continuer à traiter d’autres tâches. Une fois la tâche d’arrière-plan terminée, les résultats sont renvoyés et l’application située au-dessus de Node.js peut utiliser une fonction de déclenchement (rappel ou callback) pour poursuivre le traitement de la sortie.
Parce que Node.js évite l’utilisation de plusieurs fils, comme le font d’autres environnements, on l’appelle un environnement à fil unique, et donc une approche non bloquante est de la plus haute importance. C’est pourquoi Node.js utilise une boucle d’événement. Pour les tâches nécessitant des calculs intensifs, Node.js ne fait cependant pas partie des meilleurs outils : il existe d’autres langages et environnements de programmation qui traitent ces problèmes plus efficacement.
Dans les sections suivantes, nous allons examiner de plus près les fonctions de rappel. Pour l’instant, comprenez que les fonctions de rappel sont des déclencheurs qui sont exécutés à la fin d’une opération prédéfinie.
Modules
C’est une bonne pratique que de décomposer une fonctionnalité complexe et des morceaux de code importants en parties plus petites. Cette modularisation permet de mieux organiser la base de code, d’abstraire les implémentations et d’éviter les problèmes d’ingénierie compliqués. Pour répondre à ces besoins, les programmeurs regroupent des blocs de code source qui seront consommés par d’autres parties de code internes ou externes.
Prenons l’exemple d’un programme qui calcule le volume d’une sphère. Ouvrez votre éditeur de texte et créez un fichier nommé volumeCalculator.js
contenant le code JavaScript suivant :
const sphereVol = (radius) => {
return 4 / 3 * Math.PI * radius
}
console.log(`A sphere with radius 3 has a ${sphereVol(3)} volume.`);
console.log(`A sphere with radius 6 has a ${sphereVol(6)} volume.`);
Maintenant, exécutez le fichier en utilisant Node :
$ node volumeCalculator.js A sphere with radius 3 has a 113.09733552923254 volume. A sphere with radius 6 has a 904.7786842338603 volume.
Ici, une simple fonction a été utilisée pour calculer le volume d’une sphère, en fonction de son rayon. Imaginez que nous ayons également besoin de calculer le volume d’un cylindre, d’un cône, etc. : nous remarquons rapidement que ces fonctions spécifiques doivent être ajoutées au fichier volumeCalculator.js
, qui peut devenir une énorme collection de fonctions. Pour mieux organiser la structure, nous pouvons utiliser l’idée derrière les modules comme des paquets de code séparé.
Pour ce faire, créez un fichier séparé appelé polyhedrons.js
:
const coneVol = (radius, height) => {
return 1 / 3 * Math.PI * Math.pow(radius, 2) * height;
}
const cylinderVol = (radius, height) => {
return Math.PI * Math.pow(radius, 2) * height;
}
const sphereVol = (radius) => {
return 4 / 3 * Math.PI * Math.pow(radius, 3);
}
module.exports = {
coneVol,
cylinderVol,
sphereVol
}
Maintenant, dans le fichier volumeCalculator.js
, supprimez l’ancien code et remplacez-le par ce bout de code :
const polyhedrons = require('./polyhedrons.js');
console.log(`A sphere with radius 3 has a ${polyhedrons.sphereVol(3)} volume.`);
console.log(`A cylinder with radius 3 and height 5 has a ${polyhedrons.cylinderVol(3, 5)} volume.`);
console.log(`A cone with radius 3 and height 5 has a ${polyhedrons.coneVol(3, 5)} volume.`);
Et ensuite exécuter le nom du fichier dans l’environnement Node.js :
$ node volumeCalculator.js A sphere with radius 3 has a 113.09733552923254 volume. A cylinder with radius 3 and height 5 has a 141.3716694115407 volume. A cone with radius 3 and height 5 has a 47.12388980384689 volume.
Dans l’environnement Node.js, chaque fichier de code source est considéré comme un module, mais le mot “module” dans Node.js indique un paquet de code enveloppé comme dans l’exemple précédent. En utilisant des modules, nous avons abstrait les fonctions de volume du fichier principal, volumeCalculator.js
, réduisant ainsi sa taille et facilitant l’application de tests unitaires, ce qui est une bonne pratique lors du développement d’applications du monde réel.
Maintenant que nous savons comment les modules sont utilisés dans Node.js, nous pouvons utiliser l’un des outils les plus importants : le Node Package Manager (NPM).
L’une des principales tâches de NPM est de gérer, télécharger et installer des modules externes dans le projet ou dans le système d’exploitation. Vous pouvez initialiser un dépôt node avec la commande npm init
.
NPM posera les questions par défaut sur le nom de votre dépôt, la version, la description, etc. Vous pouvez contourner ces étapes en utilisant npm init --yes
, et la commande générera automatiquement un fichier package.json
qui décrit les propriétés de votre projet/module.
Ouvrez le fichier package.json
dans votre éditeur de texte préféré et vous verrez un fichier JSON contenant des propriétés telles que des mots-clés, des commandes de script à utiliser avec NPM, un nom, etc.
Une de ces propriétés est les dépendances qui sont installées dans votre dépôt local. NPM ajoutera le nom et la version de ces dépendances dans package.json
, ainsi que package-lock.json
, un autre fichier utilisé comme solution de repli par NPM au cas où package.json
échouerait.
Tapez ce qui suit dans votre terminal :
$ npm i dayjs
Le drapeau i
est un raccourci pour l’argument install
. Si vous êtes connecté à Internet, NPM recherchera un module nommé dayjs
dans le dépôt distant de Node.js, téléchargera le module et l’installera localement. NPM va également ajouter cette dépendance à vos fichiers package.json
et package-lock.json
. Maintenant vous pouvez voir qu’il y a un dossier appelé node_modules
, qui contient le module installé avec d’autres modules s’ils sont nécessaires. Le répertoire node_modules
contient le code réel qui va être utilisé lorsque la bibliothèque est importée et appelée. Cependant, ce répertoire n’est pas sauvegardé dans les systèmes de gestion de version utilisant Git, puisque le fichier package.json
fournit toutes les dépendances utilisées. Un autre utilisateur peut prendre le fichier package.json
et simplement exécuter npm install
sur sa propre machine, où NPM créera un dossier node_modules
avec toutes les dépendances du fichier package.json
, évitant ainsi le contrôle de version pour les milliers de fichiers disponibles sur le dépôt NPM.
Maintenant que le module dayjs
est installé dans le répertoire local, ouvrez la console Node.js et tapez les lignes suivantes :
const dayjs = require('dayjs');
dayjs().format('YYYY MM-DDTHH:mm:ss')
Le module dayjs
est chargé avec le mot-clé require
. Lorsqu’une méthode du module est appelée, la bibliothèque prend la date du système actuel et l’affiche dans le format spécifié :
2020 11-22T11:04:36
Il s’agit du même mécanisme que celui utilisé dans l’exemple précédent, où le moteur d’exécution Node.js charge la fonction tierce dans le code.
Fonctionnalité du serveur
Étant donné que Node.js contrôle l’arrière-plan des applications Web, l’une de ses tâches principales consiste à traiter les requêtes HTTP.
Voici un résumé de la manière dont les serveurs web traitaient les requêtes HTTP entrantes. La fonctionnalité du serveur consiste à écouter les demandes, à déterminer aussi rapidement que possible la réponse dont chacune a besoin et à renvoyer cette réponse à l’expéditeur de la demande. Cette application doit recevoir une requête HTTP entrante déclenchée par l’utilisateur, analyser la requête, effectuer le calcul, générer la réponse et la renvoyer. Un module HTTP tel que Node.js est utilisé car il simplifie ces étapes, permettant au programmeur web de se concentrer sur l’application elle-même.
Considérons l’exemple suivant qui met en œuvre cette fonctionnalité très basique :
const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
const queryObject = url.parse(req.url,true).query;
let result = parseInt(queryObject.a) + parseInt(queryObject.b);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(`Result: ${result}\n`);
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Sauvegardez ce contenu dans un fichier appelé basic_server.js
et exécutez-le avec une commande node
. Le terminal qui exécute Node.js affichera le message suivant :
Server running at http://127.0.0.1:3000/
Ensuite, visitez l’URL suivante dans votre navigateur web : http://127.0.0.1:3000/numbers?a=2&b=17
Node.js fait tourner un serveur web dans votre ordinateur, et utilise deux modules : http
et url
. Le module http
met en place un serveur HTTP basique, traite les requêtes web entrantes, et les transmet à notre code d’application simple. Le module URL analyse les arguments passés dans l’URL, les convertit au format entier et effectue l’opération d’addition. Le module http
envoie ensuite la réponse sous forme de texte au navigateur web.
Dans une application web réelle, Node.js est généralement utilisé pour traiter et récupérer des données, souvent à partir d’une base de données, et renvoyer les informations traitées au front-end pour affichage. Mais l’application de base de cette leçon montre de manière concise comment Node.js utilise des modules pour traiter les requêtes web en tant que serveur web.
Exercices guidés
-
Quelles sont les raisons d’utiliser des modules au lieu d’écrire des fonctions simples ?
-
Pourquoi l’environnement Node.js est-il devenu si populaire ? Citez une caractéristique.
-
A quoi sert le fichier
package.json
? -
Pourquoi n’est-il pas recommandé d’enregistrer et de partager le dossier
node_modules
?
Exercices d’exploration
-
Comment pouvez-vous exécuter des applications Node.js sur votre ordinateur ?
-
Comment délimiter les paramètres dans l’URL à analyser dans le serveur ?
-
Indiquez un scénario dans lequel une tâche spécifique pourrait constituer un goulot d’étranglement pour une application Node.js.
-
Comment implémenter un paramètre pour multiplier ou additionner les deux nombres dans l’exemple du serveur ?
Résumé
Cette leçon donne un aperçu de l’environnement Node.js, de ses caractéristiques et de la façon dont il peut être utilisé pour mettre en œuvre des programmes simples. Cette leçon comprend les concepts suivants :
-
Ce qu’est Node.js, et pourquoi il est utilisé.
-
Comment exécuter des programmes Node.js en utilisant la ligne de commande.
-
Les boucles d’événements et le single thread.
-
Modules.
-
Node Package Manager (NPM).
-
Fonctionnalité du serveur.
Réponses aux exercices guidés
-
Quelles sont les raisons d’utiliser des modules au lieu d’écrire des fonctions simples ?
En optant pour les modules au lieu des fonctions classiques, le programmeur crée une base de code plus simple à lire et à maintenir et pour laquelle il peut écrire des tests automatisés.
-
Pourquoi l’environnement Node.js est-il devenu si populaire ? Citez une caractéristique.
L’une des raisons est la flexibilité du langage JavaScript, qui était déjà largement utilisé dans le front-end des applications web. Node.js permet l’utilisation d’un seul langage de programmation dans l’ensemble du système.
-
A quoi sert le fichier
package.json
?Ce fichier contient les métadonnées du projet, comme le nom, la version, les dépendances (bibliothèques), etc. Avec un fichier
package.json
, d’autres personnes peuvent télécharger et installer les mêmes bibliothèques et exécuter des tests de la même manière que le créateur original. -
Pourquoi n’est-il pas recommandé d’enregistrer et de partager le dossier
node_modules
?Le dossier
node_modules
contient les implémentations des bibliothèques disponibles dans des dépôts distants. La meilleure façon de partager ces bibliothèques est donc de les indiquer dans le fichierpackage.json
et d’utiliser ensuite NPM pour télécharger ces bibliothèques. Cette méthode est plus simple et plus exempte d’erreurs, car vous ne devez pas suivre et maintenir les bibliothèques localement.
Réponses aux exercices d’exploration
-
Comment pouvez-vous exécuter des applications Node.js sur votre ordinateur ?
Vous pouvez les exécuter en tapant
node PATH/FILE_NAME.js
à la ligne de commande dans votre terminal, en changeantPATH
par le chemin de votre fichier Node.js et en changeantFILE_NAME.js
par le nom de votre fichier choisi. -
Comment délimiter les paramètres dans l’URL à analyser dans le serveur ?
Le caractère esperluette
&
est utilisé pour délimiter ces paramètres, afin qu’ils puissent être extraits et analysés dans le code JavaScript. -
Indiquez un scénario dans lequel une tâche spécifique pourrait constituer un goulot d’étranglement pour une application Node.js.
Node.js n’est pas un bon environnement pour exécuter des processus intensifs en termes de CPU car il utilise un seul thread. Un scénario de calcul numérique pourrait ralentir et bloquer l’ensemble de l’application. Si une simulation numérique est nécessaire, il est préférable d’utiliser d’autres outils.
-
Comment implémenter un paramètre pour multiplier ou additionner les deux nombres dans l’exemple du serveur ?
Utilisez un opérateur ternaire ou une condition if-else pour vérifier la présence d’un paramètre supplémentaire. Si le paramètre est la chaîne
mult
, retournez le produit des nombres, sinon retournez la somme. Remplacez l’ancien code par l’extrait ci-dessous. Redémarrez le serveur dans la ligne de commande en appuyant sur kbd:[Ctrl+C] et en ré-exécutant la commande pour redémarrer le serveur. Testez maintenant la nouvelle application en visitant l’URLhttp://127.0.0.1:3000/numbers?a=2&b=17&operation=mult
dans votre navigateur. Si vous omettez ou modifiez le dernier paramètre, les résultats devraient être la somme des chiffres.let result = queryObject.operation == 'mult' ? parseInt(queryObject.a) * parseInt(queryObject.b) : parseInt(queryObject.a) + parseInt(queryObject.b);