NodeJS. Objet global. Bases de Nodejs Installation de nouveaux modules

JavaScript a un objet spécial appelé objet global, lui et tous ses attributs sont accessibles n'importe où dans le programme, une variable globale.

Un navigateur JavaScript est généralement un objet de fenêtre global, un objet global Node.js est un objet global, toutes les variables globales (à l'exception du soi global) appartiennent à l'objet global.

Dans Node.js, nous avons un accès direct aux propriétés globales, sans avoir à les inclure dans l'application.

Objets globaux et variables globales

Le rôle global le plus fondamental est celui de variable hôte globale. Par définition ECMAScript, les conditions suivantes sont des variables globales :

  • La variable Externe est définie ;
  • Propriétés globales des objets ;
  • La variable est implicitement définie (affectation directe à des variables non définies).

Lorsque vous définissez une variable globale, la variable deviendra également la propriété de l'objet global, et vice versa. Notez que, dans Node.js, vous ne pouvez pas définir de variables dans un contexte externe, puisque tout le code utilisateur fait partie du module actuel et que le module lui-même n'est pas un contexte externe.

Note: utilisez toujours var pour définir des variables afin d'éviter d'introduire une variable globale, car les variables globales pollueront l'espace de noms, augmentant le risque de code de communication.

__nom de fichier

__filename spécifie le nom de fichier du script en cours d'exécution. Le chemin absolu vers l'emplacement où se trouvera le fichier de sortie, mais l'option de ligne de commande et la spécification du nom du fichier ne sont pas nécessairement les mêmes. Si dans un module, la valeur renvoyée est le chemin d'accès au fichier du module.

exemples

// Nom du fichier __filename et console.log(__filename);

$ nœud main.js /web/com/w3big/nodejs/main.js

__dirname

__dirname représente le répertoire de script actuellement situé.

exemples

Créez un fichier main.js, codez comme ceci :

// Nom du répertoire __dirname et console.log(__dirname);

Le fichier exécutable main.js, le code ressemble à ceci :

$ nœud main.js /web/com/w3big/nodejs

setTimeout (CB, ms)

setTimeout(C - Bi, mme): La fonction SetTimeout() n'est spécifiée qu'une seule fois.

Il renvoie la valeur du handle représentant le minuteur.

exemples

Créez un fichier main.js, codez comme ceci :

Function printHello())( console.log("Bonjour tout le monde !"); ) // setTimeout(printHello, 2000);

Le fichier exécutable main.js, le code ressemble à ceci :

$ node main.js Bonjour tout le monde !

clearTimeout(t)

clearTimeout(t) est utilisé pour arrêter la fonction globale avant de passer setTimeout() pour créer le timer. Paramètre Fonction T setTimeout() pour créer une calculatrice.

exemples

Créez un fichier main.js, codez comme ceci :

Fonction printHello())( console.log("Hello, World!"); ) // var t = setTimeout(printHello, 2000); // Supprimer le clearTimeout(t);

Le fichier exécutable main.js, le code ressemble à ceci :

$nodemain.js

setInterval(CB, ms)

setIntervalle(C - Bi, mme) La fonction globale exécute la fonction spécifiée après un nombre spécifié de millisecondes (ms) Nombre (CB).

Il renvoie la valeur du handle représentant le minuteur. Vous pouvez utiliser la fonction clearInterval(T) pour effacer la minuterie.

La méthode setInterval() continuera à appeler la fonction jusqu'à ce que clearInterval() soit appelée ou que la fenêtre soit fermée.

exemples

Créez un fichier main.js, codez comme ceci :

Function printHello())( console.log("Bonjour tout le monde !"); ) // setInterval(printHello, 2000);

Le fichier exécutable main.js, le code ressemble à ceci :

$ node main.js Bonjour tout le monde ! Bonjour le monde! Bonjour le monde! Bonjour le monde! Bonjour le monde! ......

Le programme ci-dessus affichera "Hello, World!" une fois toutes les deux secondes et s'exécutera en continu jusqu'à ce que le bouton soit enfoncé. CTRL + C.

console

Console La console permettant de fournir une sortie standard, qui est la fonction de débogage fournie par le moteur JScript dans Internet Explorer, et qui est devenue plus tard le navigateur standard de facto.

Node.js suit cette norme, garantissant un comportement et des habitudes cohérents de l'objet console utilisé dans les caractères de sortie du flux de sortie standard (STDOUT) ou du flux d'erreurs standard (STDERR).

méthode console

Ci-dessous se trouve l'objet console :

Non.Méthode et description
1 console.log([données] [, ... ])
Pour les caractères de flux de sortie imprimables standard et se termine par un caractère de nouvelle ligne. Cette méthode accepte plusieurs paramètres, s'il n'y a qu'un seul paramètre, alors la sortie est une chaîne de ce paramètre. S'il y a plusieurs arguments, des endroits tels que le format de sortie de la commande dans C E().
2 console.info([données] [, ... ])
Le rôle P de la commande renvoie un message d'information, la commande console.log ne fait pas beaucoup de différence, en plus de chrome, seul le texte sera affiché, le reste affichera un point d'exclamation bleu.
3 console.erreur([données] [, ... ])
Message d'erreur de sortie. La console s'affichera en rouge lorsqu'une erreur de fork se produit.
4 console.warn([données] [, ... ])
Un message d'avertissement s'affiche. La console s'affiche avec un point d'exclamation jaune.
5 console.dir(OBJ[, options])
Objet utilisé pour l'inspection (inspection) et formats d'affichage et d'impression faciles à lire.
6 console.time (raccourci)
Sortie de l'heure, heure de début.
7 console.timeEnd (raccourci)
Heure de fin, qui indique la fin des temps.
8 console.trace(message [, ...])
Le code implémente actuellement le chemin d'appel sur la pile, exécuter cette fonction de test est utile, je veux juste tester la fonction qui est rejointe par console.trace sur la ligne.
9 console.assert(valeur[, message][, ...])
Pour déterminer si une variable ou une expression est vraie, deux paramètres étaient requis, le premier paramètre est une expression et le deuxième argument est une chaîne. Ce n'est que lorsque le premier argument est faux que le résultat sera le deuxième argument ; il n'y aura aucun résultat.
console.log() : Imprime sur la sortie standard et termine par une nouvelle ligne.

console.log accepte plusieurs paramètres, s'il n'y a qu'un seul paramètre, la chaîne de sortie de ce paramètre. S'il y a plusieurs arguments, des endroits tels que le format de sortie de la commande dans C E().

Le premier paramètre est une chaîne, pas de paramètres, imprimez simplement un caractère de nouvelle ligne.

Console.log("Bonjour tout le monde"); console.log("byvoid%diovyb"); console.log("byvoid%diovyb", 1991);

Bonjour tout le monde byvoid%diovyb byvoid1991iovyb

  • console.error() : Avec console.log(), cela fait la même chose, mais génère une erreur standard.
  • console.trace() : diffuse les erreurs vers la sortie standard de la pile d'appels actuelle.
console.trace();

Résultats opérationnels comme suit :

Trace : à l'objet. (/home/byvoid/consoletrace.js:1:71) sur Module._compile (module.js:441:26) sur Object..js (module.js:459:10) sur Module.load (module.js : 348:31) sur Function._load (module.js:308:12) sur Array.0 (module.js:479:10) sur EventEmitter._tickCallback (node.js:192:40)

exemples

Créez un fichier main.js, codez comme ceci :

Console.info("程序开始执行:"); compteur var = 10 ; console.log("计数: %d", compteur); console.time("获取数据"); // // 执行一些代码 // console.timeEnd("获取数据"); console.info("程序执行完毕。")

Le fichier exécutable main.js, le code ressemble à ceci :

$ node main.js Type de fichier : Nom : 10 nœuds : 0 ms

processus

Un processus est une variable globale, un attribut est un objet global.

Il est utilisé pour décrire l'état actuel du processus d'un objet Node.js et fournit une interface simple avec le système d'exploitation. Habituellement, vous écrivez vos propres programmes en ligne de commande et vous finissez par vous en occuper. Ci-dessous, nous présenterons certaines des méthodes de processus d'objection les plus couramment utilisées par les membres.

Non.Événements et description
1 sortie
Se déclenche lorsque le processus est prêt à s'arrêter.
2 avantSortie
Cet événement est déclenché lorsque le nœud a une boucle d'événement vide et qu'aucune autre action n'est entreprise. En général, il n'existe aucun processus pour organiser un nœud de sortie, mais les écouteurs "beforeExit" peuvent être appelés de manière asynchrone afin que le nœud continue.
3 exception non interceptée
Lorsqu'une exception est réintégrée dans la boucle d'événements, déclenchez cet événement. Si vous ajoutez un moniteur à une exception, l'action par défaut (impression de pile et sortie) ne se produira pas.
4 Le signal est déclenché lorsque
événement lorsque le processus reçoit un signal.
Consultez la liste des noms de signaux POSIX standard tels que SIGINT, SIGUSR1, etc.

exemples

Créez un fichier main.js, codez comme ceci :

Process.on("exit", function(code) ( // setTimeout(function() ( console.log("该代码不会执行"); 0); console.log("退出码为:", code) ; )); console.log("程序执行结束");

Le fichier exécutable main.js, le code ressemble à ceci :

$ node main.js valeur de référence : 0

Codes d'état de sortie

Les codes d'état de sortie sont les suivants :

Code d'étatTitre et description
1 Exception fatale non détectée
Il existe une exception non interceptée et elle n’a pas été gérée ni par le domaine du gestionnaire uncaughtException.
2 inutilisé
rétention
3 Analyse des erreurs internes JavaScript
Le code source d’analyse des erreurs JavaScript est appelé au démarrage du processus Node. Très rarement, uniquement lorsque Node.
4 Score de panne JavaScript interne
Le processus JavaScript exécutant le nœud source renvoie un échec lors de l'évaluation de la fonction. Très rarement, uniquement lorsque Node.
5 Erreur fatale
V8 dans une erreur irréparable avec une issue fatale. Imprime généralement Stderr, contenu : erreur fatale
6 Gestionnaire d’exceptions internes sans fonction
Exception non interceptée, le gestionnaire d'exceptions à l'intérieur est en quelque sorte défini sur la fonction et ne peut pas non plus être appelé.
7 Échec d’exception du gestionnaire d’exécution interne
Exception non interceptée et le gestionnaire d'exceptions pour gérer le sien lève une exception. Par exemple, si process.on("uncaughtException") ou domain.on("error") lève une exception.
8 inutilisé
rétention
9 Argument invalide
Il peut s'agir de paramètres inconnus ou d'un paramètre à valoriser.
10 Échec de l'exécution JavaScript interne
Le code source JavaScript est généré lorsque des erreurs sont déclenchées dans le processus Node, très rarement, uniquement lors du développement de Node.
12 Argument de débogage invalide
L'option --debug est définie et/ou --debug-BRK, mais le mauvais port est sélectionné.
> 128 Sorties de signaux
Si un nœud reçoit un signal fatal, tel que SIGKILL ou SIGHUP, alors le code retour est 128 plus le code du signal. Il s'agit d'une pratique Unix standard, du code élevé sur les signaux de sortie.

attributs de processus

Le processus offre de nombreuses propriétés utiles, une facilité d'interaction, qui nous permettent de mieux contrôler le système :

Qté.Propriété et description
1 SORTIE STD
Flux de sortie standard.
2 STDERR
Flux d’erreurs standard.
3 STDIN
Flux d’entrée standard.
4 ARGV
La propriété ARGV renvoie un tableau de diverses options pour exécuter un script de ligne de commande lors de la composition. Ses premiers membres sont toujours un nœud, son deuxième membre est le nom du fichier de script et les membres restants sont des paramètres du fichier de script.
5 execPath
Renvoie le chemin absolu du nœud binaire d'exécution du script actuel.
6 execArgv
Renvoie le membre du tableau situé sous le script de ligne de commande exécuté entre les paramètres de ligne de commande exécutables du nœud du fichier de script.
7 ENV
Renvoie un objet, les membres de la variable d'environnement shell actuelle
8 Code de sortie
Le code de sortie du processus, si le processus est présenté avec la sortie process.exit(), sans spécifier de code de sortie.
9 version
version du nœud, telle que v0.10.18.
10 versions
Propriété qui contient les versions des nœuds et des dépendances.
11 configuration
L'objet qui contient le nœud actuel est utilisé pour compiler le fichier de configuration des options javascript exécutable. Il s'agit du même script run./configure créé par le fichier "config.gypi".
12 PID- régulateur
Numéro de processus actuel.
13 Nom
Nom du processus, "nœud" par défaut, vous pouvez personnaliser la valeur.
14 cambre
Architecture CPU actuelle : "arm", "ia32" ou "64".
15 plate-forme
Exécutez le programme dont la plateforme est "Darwin", "FreeBSD", "Linux", "SunOS" ou "win32"
16 module principal
require.main méthodes alternatives. Divers points, si le module principal change au moment de l'exécution, require.main peut continuer à revenir à l'ancien module. Les deux sont considérés comme appartenant au même module.

exemples

Créez un fichier main.js, codez comme ceci :

// Retour au début process.stdout.write("Hello World!" + "\n"); // La fonction process.argv.forEach(function(val, index, array) ( console.log(index + ": " + val); )); // Fichier de commande console.log(process.execPath); // Utilisation de console.log(process.platform);

Le fichier exécutable main.js, le code ressemble à ceci :

$ node main.js Bonjour tout le monde ! 0 : nœud 1 : /web/www/node/main.js /usr/local/node/0.10.36/bin/node darwin

Guide de référence des méthodes

Le processus fournit de nombreuses méthodes utiles pour faciliter un contrôle plus efficace de notre système interactif :

Non.Méthode et description
1 avorter()
Cela déclenchera l’événement déclencheur du nœud d’interruption. Cela entraînera la fermeture du nœud et la création d'un fichier de vidage.
2 ChDir (répertoire)
Modifiez le répertoire de travail actuel du processus si l'opération ne peut pas se terminer.
3 OREILLE ()
Renvoie le répertoire de travail du processus en cours
4 quitter([code])
Termine le processus avec le code spécifié. Si ce paramètre est omis, il utilisera le code 0.
5 getgid()
Obtenez l'identification du groupe de processus (voir getgid(2)). Lorsqu'un groupe a acheté une identification numérique plutôt qu'un nom.
6 setgid(ID)
Mise en place du processus d'identification de groupe (voir setgid (2)). L'ID peut prendre un nom numérique ou de groupe. Si vous spécifiez un nom de groupe, le blocage sera autorisé en attendant une identification numérique.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
7 getuid()
Obtenez le processus d'identification de l'utilisateur (voir getuid(2)). Il s'agit d'un identifiant d'utilisateur numérique et non d'un nom d'utilisateur.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
8 UIP (ID)
ID utilisateur de configuration du processus (voir UIP (2)). Récupération d'un identifiant numérique ou d'une chaîne de nom. Si vous spécifiez un nom de groupe, le blocage sera autorisé en attendant une identification numérique.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
9 obtenir des groupes()
Le processus de renvoi du tableau d’ID de groupe. Le système POSIX ne garantit pas que ce soit le cas, mais Node.js est garanti d'être là.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
10 définir des groupes
Définissez l'ID du groupe de processus. Il est éligible pour fonctionner, tout ce dont vous avez besoin est d'avoir les privilèges de superutilisateur ou d'avoir la capacité CAP_SETGID.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
11 initgroups (utilisateur, extra_group)
Lecture / etc. /group et initialise la liste d'accès au groupe, tous les membres du groupe sont localisés. Il est éligible pour fonctionner, tout ce dont vous avez besoin est d'avoir les privilèges de superutilisateur ou d'avoir la capacité CAP_SETGID.
Remarque : Cette fonction ne peut être utilisée (par exemple, non-Windows et Android) que sur les plates-formes POSIX.
12 tuer (IDP [signal])
Envoie un signal à un processus. L'ID est l'identifiant du processus et le signal est une chaîne indiquant le signal en cours de transmission. Les noms de signaux sont des chaînes comme "SIGINT" ou "" SIGHUP. Si ce paramètre est omis, le signal sera "SIGTERM".
13 Utilisation de la mémoire()
Il renvoie un objet qui décrit le processus utilisé par les octets d'état de la mémoire du nœud.
14 nextTick (rappel)
Après la fin de la boucle d’événements de rappel de fonction actuelle.
15 Umasque ([masque])
Définir ou lire le fichier de masque de processus. Les processus enfants héritent de ce masque du processus parent. Si l'argument du masque est vrai, alors il renvoie l'ancien masque. Sinon, il renvoie le masque actuel.
16 Dépensé()
Renvoie le nombre de secondes pendant lesquelles Node a déjà démarré.
17 heure()
Résolution temporelle du processus en cours, spécifiée en [secondes] nanosecondes du tableau. Ceci est relatif à tout événement passé. Cette valeur n’a rien à voir avec la date, elle n’affecte donc pas la dérive de l’horloge. L’objectif principal est sur une période de temps précise de mesurer les performances du programme.
Avant que le résultat puisse être transmis au process.hrtime() actuel, il renverra la différence de temps entre eux, pour la mesure de référence et d'intervalle de temps.

exemples

Créez un fichier main.js, codez comme ceci :

// Utilisation de console.log("Application: " + process.cwd()); // Affichage de la console console.log("Application : " + process.version); // Utilisation de console.log(process.memoryUsage());

​Hé les gars, dans l'article d'aujourd'hui, je veux parler des variables globales dans Node. Cet article s'adresse aux développeurs qui ont un niveau de compétence débutant à intermédiaire travaillant avec Node. Si vous n'avez jamais entendu parler de variables globales ni travaillé avec elles, non Ne vous inquiétez pas. Cet article vous permettra d'être opérationnel en un rien de temps avec tout ce que vous devez savoir sur les variables globales.

Que sont les variables globales ?

Les variables globales sont très similaires, voire identiques, aux variables régulières. Les variables globales peuvent être initialisées avec une valeur, cette valeur peut être modifiée et elles peuvent même être effacées comme une variable ordinaire. La différence entre une variable régulière et une variable globale réside dans leur portée. Lorsque vous créez une variable dans un fichier JavaScript, cette variable n'existe que dans la portée dans laquelle elle a été déclarée. Maintenant, qu’est-ce que je veux dire par là ? Dans le code ci-dessous, vous pouvez voir un exemple de deux variables différentes avec des portées différentes.

// Scope.js let fileScope = "Accessible n'importe où dans le fichier"; function doSomething() ( let localScope = "Accessible uniquement à l'intérieur de cette fonction"; fileScope = "Peut également être consulté dans la fonction!"; ) // Cela entraînera une erreur car la variable n'existe pas // en dehors de fonction. localScope = "Essayez de me changer ici";

Dans l'extrait de code ci-dessus, nous pouvons voir qu'il existe deux variables, fileScope et localScope . La variable fileScope peut être modifiée ou appelée depuis n'importe où dans ce fichier, alors que la variable localScope n'existe qu'à l'intérieur de la fonction doSomething() . Je suis sûr qu'à ce stade, vous vous demandez ce que cela a à voir avec les variables globales. Lorsque nous parlons de variables globales, elles existent pour tous les fichiers d'un programme, ce qui signifie qu'elles ont une portée globale pour le programme.

La raison pour laquelle cela est possible est que les programmes JavaScript partagent un espace de noms global entre tous les fichiers du programme. En d’autres termes, imaginez que votre programme est un fichier ou un conteneur géant qui a « importé » tous les autres fichiers JavaScript. Vous déclarez ensuite une variable dans ce gros fichier conteneur, cette variable a désormais une portée dans tout le programme. Si vous n'êtes pas sûr de ce qu'est un espace de noms ou si vous souhaitez en savoir plus à leur sujet, consultez cet article pour en savoir plus.

Comment déclarer et utiliser une variable globale

Maintenant que nous comprenons mieux ce qu'est une variable globale dans Node, parlons de la façon dont nous configurons et utilisons réellement une variable globale. Pour configurer une variable globale, nous devons la créer sur l'objet global. L'objet global est ce qui nous donne la portée de l'ensemble du projet, plutôt que simplement le fichier (module) dans lequel la variable a été créée. Dans le bloc de code ci-dessous, nous créons une variable globale appelée globalString et nous lui donnons une valeur. Ensuite, nous changeons la valeur de globalString , puis finalement nous la définissons sur undefined.

// Global.js global.globalString = "Ceci est accessible n'importe où !"; console.log(globalString); // Résultat : "Ceci est accessible n'importe où !" globalString = "Vérifiez-moi maintenant"; console.log(globalString); // Sortie : "Vérifiez-moi maintenant" globalString = undefined; console.log(globalString); // Sortie : non définie // Exemple.js // Nous pouvons également utiliser le global que nous avons créé dans Global.js dans ce fichier //. console.log(globalString); // Sortie : undefined globalString = "Nous pouvons le changer aussi !"; console.log(globalString); // Sortie : "Nous pouvons le changer aussi !"

Ce dont je n'ai pas encore parlé, c'est d'une autre façon de rendre une variable globale. La raison pour laquelle j'ai exclu cela est que ce n'est pas une manière appropriée de configurer une variable. Si vous déclarez une variable dans un fichier sans utiliser le mot-clé var puis lui attribuez une valeur, l'objet global définira une propriété pour cette variable. Ce processus en fait essentiellement une variable accessible globalement. Je déconseille fortement d'utiliser cette méthode car ce n'est pas la bonne façon de créer des globaux. Il est également important de noter que si vous définissez la directive "use strict", Node désactivera les globales implicites et vous vous retrouverez probablement avec une erreur au moment de l'exécution plutôt qu'avec un script fonctionnel.

Cas d'utilisation pratiques des variables globales

Maintenant, vous pensez peut-être que vous voulez créer des variables globales maintenant que vous en savez plus à leur sujet. Je vais fortement mettre en garde contre la création de variables globales pour quelques raisons très importantes.

La première raison est que lorsque vous créez une variable globale, elle existe pendant toute la durée de vie de l'application. Lorsqu'une variable persiste pendant toute la durée de vie de l'application, cela signifie qu'elle est là, en mémoire, occupant des ressources pendant l'exécution de l'application.

Deuxièmement, l’utilisation traditionnelle de variables globales peut entraîner des problèmes de concurrence. Si plusieurs threads peuvent accéder à la même variable et qu'aucun modificateur d'accès ou sécurité n'est en place, cela peut entraîner de graves problèmes lorsque deux threads tentent d'accéder et d'utiliser la même variable. Cependant, même si c'est le cas dans d'autres langages, ce n'est pas nécessairement le cas pour Node.js car il s'agit strictement d'un environnement monothread. Pendant qu'il est Il est possible de regrouper les processus Node, il n'existe aucun moyen natif de communiquer entre eux.

La dernière raison dont je vais parler est que l'utilisation de variables globales peut provoquer un couplage implicite entre des fichiers ou des variables. Le couplage n’est pas une bonne chose lorsqu’il s’agit d’écrire du bon code. Lors de l’écriture du code, nous voulons nous assurer qu’il est aussi modulaire et réutilisable que possible, tout en nous assurant qu’il est facile à utiliser et à comprendre. Le couplage de morceaux de votre code peut entraîner des problèmes majeurs lorsque vous essayez de déboguer pourquoi quelque chose ne fonctionne pas.

Si vous souhaitez en savoir plus sur les raisons pour lesquelles les variables globales ne sont pas recommandées, vous pouvez consulter cet excellent article intitulé Les variables globales sont mauvaises.

Si vous ne comprenez pas le but des variables globales, n’ayez crainte. Nous allons examiner quelques-unes des variables globales intégrées à Node et essayer de mieux comprendre pourquoi elles sont globales et comment elles sont utilisées. En fait, vous en avez probablement déjà utilisé quelques-uns sans même vous rendre compte qu’il s’agit d’objets globaux !

// Node Globals console.log("Hello World!"); processus.env.PORT = 3000 ; setInterval(( console.log("2 secondes écoulées."); 2000);

Si vous jetez un œil au bloc de code ci-dessus, vous verrez probablement au moins une instance que vous avez utilisée auparavant, console.log() . Selon la documentation de Node, l'objet console est un objet global doté de quelques méthodes permettant aux développeurs de faire des choses telles que l'impression d'un journal ou d'une erreur. En creusant plus profondément dans la documentation, nous pouvons voir que la console est en réalité une instance globale configurée pour écrire dans process.stdout et process.stderr .

Cela nous amène à l'instruction suivante que vous voyez dans le bloc de code ci-dessus, l'objet processus. Si vous avez mis en place une version de production d'une application Node, vous avez probablement dû définir le port de la variable d'environnement. La variable d'environnement env fait partie de l'objet processus qui est un autre global. Vous pouvez accéder aux variables de l'objet de processus dans n'importe quel fichier de votre projet car il est global. Si cet objet n'était pas global, l'objet console ne serait pas non plus accessible depuis n'importe quel fichier, rappelez-vous qu'il s'agit en réalité d'un objet qui fait référence à l'objet processus.

setInterval est une autre fonction que vous avez peut-être déjà vue si vous avez déjà eu des raisons de retarder une opération avant de l'exécuter. setTimeout et setImmediate sont de nature similaire à setInterval et sont également des fonctions globales. Ces trois fonctions font partie du module timer qui expose une API globale vous permettant d'appeler ces fonctions sans nécessiter explicitement de timer dans vos fichiers.

​Tous les cas d'utilisation mentionnés ci-dessus sont intégrés à Node et sont globaux pour une raison. L'objet processus est global car il fournit des informations sur le processus Node en cours d'exécution et doit donc être disponible à partir de n'importe quel fichier sans avoir à l'exiger. La même chose peut être dite du module minuterie qui contient un certain nombre de fonctions importantes et qui doivent être accessibles partout sans avoir à en avoir besoin. Si vous souhaitez en savoir plus sur les objets globaux existants intégrés à Node, je vous encourage à visiter la documentation officielle sur Globals.

Apprendre encore plus

Vous souhaitez en savoir plus sur les fondamentaux de Node.js ? Personnellement, je recommanderais un cours en ligne, comme Wes Bos "Learn Node.js", car les vidéos sont beaucoup plus faciles à suivre et vous pourrez réellement créer une application réelle.

Conclusion

​Je sais que c'était pas mal d'informations, alors merci d'avoir tenu le coup. Toutes les informations ci-dessus ont été trouvées dans la documentation sur le site Web de Node. N'hésitez pas à poser des questions et à faire des commentaires dans la section commentaires ci-dessous. À la prochaine fois les gars !

Un étudiant a demandé : « Les programmeurs d’autrefois utilisaient uniquement des ordinateurs simples et programmaient sans langage, mais ils créaient de beaux programmes. Pourquoi utilisons-nous des ordinateurs et des langages de programmation complexes ? » Fu-Tzu répondit : « Les constructeurs d’autrefois n’utilisaient que des bâtons et de l’argile, mais ils fabriquaient de belles huttes. »

Maître Yuan-Ma, « Livre de Programmation »

Jusqu'à présent, vous avez appris JavaScript et l'avez utilisé dans un seul environnement : le navigateur. Dans ce chapitre et le suivant, nous présenterons brièvement Node.js, un programme qui vous permet d'utiliser les compétences JavaScript en dehors du navigateur. Avec lui, vous pouvez tout écrire, des utilitaires de ligne de commande aux serveurs HTTP dynamiques.

Ces chapitres se concentrent sur l'enseignement des idées importantes qui composent Node.js et sont conçus pour vous donner suffisamment d'informations pour vous permettre d'écrire des programmes utiles dans le framework. Ils n’essaient pas d’être des références complètes pour Node.

Vous pouvez écrire et exécuter le code des chapitres précédents directement dans le navigateur, mais le code de ce chapitre a été écrit pour Node et ne fonctionnera pas dans le navigateur.

Si vous souhaitez exécuter le code de ce chapitre immédiatement, commencez par installer Node depuis nodejs.org pour votre système d'exploitation. Vous trouverez également sur ce site de la documentation sur Node et ses modules intégrés.

Introduction

L'un des problèmes les plus difficiles lors de l'écriture de systèmes communiquant sur un réseau est la gestion des entrées et des sorties. Lecture et écriture de données vers et depuis le réseau, le disque et d'autres appareils. Le déplacement de données prend du temps, et une bonne planification de cette activité peut avoir un impact considérable sur le temps de réponse du système aux demandes des utilisateurs ou du réseau.

Dans le traitement d'entrée et de sortie traditionnel, une fonction telle que readFile commence à lire le fichier et ne revient que lorsque le fichier a été complètement lu. C'est ce qu'on appelle les E/S synchrones (entrée/sortie).

Node a été conçu pour rendre les E/S asynchrones de plus en plus faciles à utiliser. Nous avons déjà vu des interfaces asynchrones, telles que l'objet navigateur XMLHttpRequest, abordé au chapitre 17. Une telle interface permet au script de continuer à s'exécuter pendant que l'interface fait son travail et appelle une fonction de rappel lorsqu'elle est terminée. C'est ainsi que fonctionnent toutes les E/S dans Node.

JavaScript s'intègre facilement dans un système comme Node. C’est l’un des rares langages à ne pas intégrer de système d’E/S. Ainsi, JavaScript s'intègre facilement dans l'approche plutôt excentrique de Node en matière d'E/S et ne finit pas par donner naissance à deux systèmes d'entrée et de sortie différents. En 2009, lors du développement de Node, les utilisateurs utilisaient déjà des E/S basées sur le rappel dans le navigateur, la communauté autour du langage était donc habituée à un style de programmation asynchrone.

Asynchronie

Je vais essayer d'illustrer la différence entre les approches synchrones et asynchrones des E/S avec un petit exemple, dans lequel un programme doit recevoir deux ressources d'Internet, puis faire quelque chose avec les données.

Dans un environnement synchrone, la manière évidente de résoudre le problème consiste à effectuer des requêtes de manière séquentielle. Cette méthode a un inconvénient : la deuxième requête ne démarrera qu'une fois la première terminée. Le temps total ne sera pas inférieur à la somme du temps de traitement de deux demandes. Il s’agit d’une utilisation inefficace de l’ordinateur, qui restera inactif la plupart du temps pendant le transfert des données sur le réseau.

La solution au problème dans un système synchrone consiste à lancer des threads de contrôle d'exécution de programme supplémentaires (nous en avons déjà discuté au chapitre 14). Un deuxième thread peut exécuter une deuxième requête, puis les deux threads attendront que le résultat soit renvoyé, après quoi ils seront resynchronisés pour faire converger le travail en un seul résultat.

Dans le diagramme, les lignes épaisses indiquent le temps de fonctionnement normal du programme et les lignes fines indiquent le temps d'attente des E/S. Dans le modèle synchrone, le temps consacré aux E/S est inclus dans le planning de chaque thread. En asynchrone, le démarrage d'une action via les E/S entraîne un branchement de la ligne temporelle. Le thread qui a lancé l'E/S continue son exécution et l'E/S est exécutée en parallèle, effectuant un rappel de fonction une fois terminée.

Déroulement du programme pour les E/S synchrones et asynchrones

Autre façon d'exprimer cette différence : dans le modèle synchrone, l'attente de la fin des E/S est implicite, mais dans le modèle asynchrone, elle est explicite, et est sous notre contrôle direct. Mais l’asynchronie fonctionne dans les deux sens. Cela facilite l'expression de programmes non linéaires, mais rend plus difficile l'expression de programmes linéaires.

Au chapitre 17, j'ai déjà évoqué le fait que les rappels introduisent beaucoup de bruit et rendent un programme moins organisé. La question de savoir si cette approche est généralement une bonne idée est discutable. Dans tous les cas, il faut du temps pour s'y habituer.

Mais pour un système basé sur JavaScript, je dirais que l'utilisation de l'asynchrone avec des rappels est logique. L’un des points forts de JavaScript est sa simplicité, et essayer d’ajouter plusieurs threads à un programme entraînerait une grande complexité. Bien que les rappels ne simplifient pas le code, l'idée qui les sous-tend est très simple et pourtant suffisamment puissante pour vous permettre d'écrire des serveurs Web hautes performances.

commande de nœud

Lorsque Node.js est installé sur votre système, vous disposez d'un programme appelé node qui exécute des fichiers JavaScript. Supposons que vous ayez un fichier hello.js avec le code suivant :

Var message = "Bonjour tout le monde" ; console.log(message);

Vous pouvez exécuter votre programme à partir de la ligne de commande :

$node hello.js Bonjour tout le monde

La méthode console.log dans Node fonctionne de la même manière que dans le navigateur. Affiche un morceau de texte. Mais dans Node, le texte est imprimé sur la sortie standard plutôt que sur la console JavaScript du navigateur.

Si vous exécutez node sans fichier, il vous donnera une chaîne de requête dans laquelle vous pourrez écrire du code JavaScript et obtenir le résultat.

$ nœud > 1 + 1 2 > [-1, -2, -3].map(Math.abs) > ​​​​process.exit(0) $

La variable de processus, comme la console, est disponible globalement dans Node. Il propose plusieurs façons d’inspecter et de manipuler un programme. La méthode exit termine le processus et peut recevoir un code d'état de sortie du programme, qui indique au programme qui a lancé le nœud (dans ce cas, le shell) si le programme s'est terminé avec succès (code zéro) ou a échoué (tout autre nombre).

Pour accéder aux arguments de ligne de commande transmis au programme, vous pouvez lire le tableau de chaînes process.argv. Il inclut également le nom de la commande de nœud et le nom de votre script, de sorte que la liste d'arguments commence à l'index 2. Si le fichier showargv.js ne contient qu'une instruction console.log(process.argv), vous pouvez l'exécuter comme ceci :

$ node showargv.js un --et deux ["node", "/home/marijn/showargv.js", "one", "--and", "two"]

Toutes les variables globales JavaScript standard - Array, Math, JSON, sont également disponibles dans l'environnement Node. Mais il n'existe aucune fonctionnalité liée au navigateur, telle qu'un document ou une alerte.

L'objet de portée globale, appelé window dans le navigateur, est appelé de manière plus significative global dans Node.

Modules

Hormis quelques variables mentionnées comme la console et le processus, Node conserve peu de fonctionnalités dans la portée globale. Pour accéder au reste des fonctionnalités intégrées, vous devez accéder au système de modules.

Le système CommonJS, basé sur la fonction require, a été décrit au chapitre 10. Ce système est intégré à Node et est utilisé pour tout charger, des bibliothèques intégrées et téléchargées aux fichiers qui font partie de votre programme.

Lorsque vous appelez require Node, vous devez convertir la chaîne donnée en nom de fichier. Les chemins commençant par "/", "./" ou "../" sont convertis en chemins relatifs au chemin actuel. "./" signifie le répertoire actuel, "../" signifie le répertoire ci-dessus et "/" signifie le répertoire racine du système de fichiers. Si vous demandez "./world/world" à partir du fichier /home/marijn/elife/run.js, Node essaiera de charger le fichier /home/marijn/elife/world/world.js. L'extension .js peut être omise.

Lorsqu'une chaîne qui ne semble pas être un chemin relatif ou absolu est transmise, il est supposé qu'il s'agit soit d'un module intégré, soit d'un module installé dans le répertoire node_modules. Par exemple, require("fs") vous donnera un module intégré pour travailler avec le système de fichiers, et require("elife") essaiera de charger la bibliothèque depuis node_modules/elife/. La méthode typique pour installer des bibliothèques consiste à utiliser NPM, sur laquelle je reviendrai plus tard.

Pour démontrer, créons un simple projet à deux fichiers. Le premier s'appellera main.js, et il définira un script appelé depuis la ligne de commande, conçu pour déformer les chaînes.

Var garble = require("./garble"); // L'index 2 contient le premier argument du programme de la ligne de commande var argument = process.argv; console.log(garble(argument));

Le fichier garble.js définit une bibliothèque de modification de chaînes qui peut être utilisée à la fois par le programme de ligne de commande que vous avez défini précédemment et par d'autres scripts nécessitant un accès direct à la fonction garble.

Module.exports = function(string) ( return string.split("").map(function(ch) ( return String.fromCharCode(ch.charCodeAt(0) + 5); )).join(""); ) ;

Remplacer module.exports au lieu d'y ajouter des propriétés nous permet d'exporter une valeur spécifique à partir d'un module. Dans ce cas, le résultat de la requête de notre module sera la fonction de distorsion elle-même.

La fonction divise une chaîne en caractères en utilisant split avec une chaîne vide, puis remplace tous les caractères par d'autres par un code 5 unités plus haut. Il concatène ensuite le résultat dans une chaîne.

Nous pouvons maintenant appeler notre outil :

$ node main.js JavaScript De(fXhwnuy

Installation via NPM

NPM, mentionné brièvement au chapitre 10, est un référentiel en ligne de modules JavaScript, dont beaucoup sont écrits spécifiquement pour Node. Lorsque vous installez Node sur votre ordinateur, vous obtenez un programme npm qui fournit une interface pratique avec ce référentiel.

Par exemple, l'un des modules NPM s'appelle figlet et convertit le texte en « art ASCII », des dessins composés de caractères de texte. Voici comment l'installer :

$ npm install figlet npm GET https://registry.npmjs.org/figlet npm 200 https://registry.npmjs.org/figlet npm GET https://registry.npmjs.org/figlet/-/figlet-1.0. 9.tgz npm 200 https://registry.npmjs.org/figlet/-/figlet-1.0.9.tgz [email protégé] node_modules/figlet $ node > var figlet = require("figlet"); > figlet.text("Bonjour tout le monde !", function(erreur, données) ( if (erreur) console.error(erreur); else console.log(data); )); _ _ _ _ _ _ _ | | | | ___| | | ___ __ _____ _ __| | __| | | | |_| |/ _ \ | |/ _ \ \ \ /\ / / _ \| "__| |/ _` | | | _ | __/ | | (_) | \ V V / (_) | | | | (_| |_| |_| |_|\___|_|_|\ ___/ \_/\_/ \___/|_| |_|\__,_(_)

Après avoir exécuté npm install, NPM créera un répertoire node_modules. À l’intérieur, il y aura un répertoire figlet contenant la bibliothèque. Lorsque nous démarrons node et appelons require("figlet"), la bibliothèque est chargée et nous pouvons appeler sa méthode text pour imprimer de grosses lettres fantaisistes.

Ce qui est intéressant, c'est qu'au lieu de simplement renvoyer une chaîne contenant des majuscules, figlet.text accepte une fonction de rappel à laquelle il transmet le résultat. Il y passe également un autre argument, error, qui contiendra un objet error en cas d'erreur, et null en cas de succès.

Ce principe de fonctionnement est adopté dans Node. Pour créer des lettres, figlet doit lire un fichier du disque contenant des lettres. La lecture d'un fichier est une opération asynchrone dans Node, donc figlet.text ne peut pas renvoyer le résultat immédiatement. L'asynchronie est contagieuse - toute fonction qui appelle une fonction asynchrone devient elle-même asynchrone.

NPM est plus qu'une simple installation npm. Il lit les fichiers package.json, qui contiennent des informations JSON sur le programme ou la bibliothèque, en particulier sur les bibliothèques sur lesquelles il est basé. L'exécution de npm install sur le répertoire contenant un tel fichier installera automatiquement toutes les dépendances, et à leur tour leurs dépendances. L'outil npm est également utilisé pour héberger des bibliothèques sur le référentiel en ligne NPM afin que d'autres personnes puissent les trouver, les télécharger et les utiliser.

Nous n’entrerons pas plus dans les détails de l’utilisation de NPM. Voir npmjs.org pour la documentation sur la recherche dans la bibliothèque.

module de système de fichiers

L'un des modules Node intégrés les plus populaires est le module « fs », qui signifie « système de fichiers ». Le module fournit des fonctionnalités pour travailler avec des fichiers et des répertoires.

Par exemple, il existe une fonction readFile qui lit un fichier et effectue un rappel avec le contenu du fichier.

Var fs = require("fs"); fs.readFile("file.txt", "utf8", function(error, text) ( if (error) throw error; console.log("Et le fichier contenu :", text); ));

Le deuxième argument de readFile spécifie le codage de caractères dans lequel convertir le contenu du fichier en chaîne. Le texte peut être converti en données binaires de plusieurs manières, mais la plus récente est UTF-8. Si vous n'avez aucune raison de croire que le fichier contient du texte dans un encodage différent, vous pouvez transmettre en toute sécurité le paramètre « utf8 ». Si vous ne spécifiez pas d'encodage, Node vous donnera les données codées en binaire sous forme d'objet Buffer plutôt que de chaîne. Il s'agit d'un objet de type tableau contenant les octets d'un fichier.

Var fs = require("fs"); fs.readFile("file.txt", function(error, buffer) ( if (error) throw error; console.log("Le fichier contenait ", buffer.length, " octets.", "Premier octet :", buffer ); ));

Une fonction similaire, writeFile, est utilisée pour écrire un fichier sur le disque.

Var fs = require("fs"); fs.writeFile("graffiti.txt", "Le nœud était ici", function(err) ( if (err) console.log("Rien n'a fonctionné, et voici pourquoi :", err); else console.log("Écriture réussie . Tout le monde est libre."); ));

Il n'est pas nécessaire de définir l'encodage ici, car writeFile suppose que si on lui donne une chaîne à écrire, et non un objet Buffer, alors elle doit être sortie sous forme de texte avec l'encodage par défaut UTF-8.

Le module « fs » contient beaucoup de choses utiles : la fonction readdir renvoie une liste de fichiers dans un répertoire sous forme de tableau de chaînes, stat renverra des informations sur un fichier, rename renomme un fichier, dissocier les suppressions, etc. Voir la documentation sur nodejs.org

De nombreuses fonctions fs ont des options synchrones et asynchrones. Par exemple, il existe une version synchrone de la fonction readFile appelée readFileSync.

Var fs = require("fs"); console.log(fs.readFileSync("file.txt", "utf8"));

Les fonctions synchrones sont plus faciles à utiliser et plus utiles pour les scripts simples où la vitesse supplémentaire d'une méthode asynchrone n'est pas importante. Mais notez que pendant l'exécution de l'action synchrone, votre programme s'arrête complètement. S'il doit répondre aux entrées de l'utilisateur ou à d'autres programmes sur le réseau, l'attente d'E/S synchrones entraîne des retards gênants.

Module HTTP

Un autre module principal est « http ». Il fournit des fonctionnalités pour créer des serveurs HTTP et des requêtes HTTP.

Voici tout ce dont vous avez besoin pour démarrer un simple serveur HTTP :

Var http = require("http"); var server = http.createServer(function(request, réponse) ( réponse.writeHead(200, ("Content-Type": "text/html")); réponse.write("

Bonjour!

Vous avez requis " + requête.url + "

"); réponse.end(); )); serveur.écouter(8000);

En exécutant le script sur votre machine, vous pouvez pointer votre navigateur vers localhost :8000/hello, créant ainsi une requête au serveur. Il répondra avec une petite page HTML.

La fonction passée en argument à createServer est appelée à chaque tentative de connexion au serveur. Les variables de requête et de réponse sont des objets représentant les données d'entrée et de sortie. La première contient des informations sur la requête, par exemple la propriété url contient l'URL de la requête.

Pour renvoyer quelque chose, les méthodes de l'objet de réponse sont utilisées. Le premier, writeHead, écrit les en-têtes de réponse (voir chapitre 17). Vous lui donnez un code d'état (dans ce cas 200 pour « OK ») et un objet contenant les valeurs d'en-tête. Ici, nous disons au client qu'il doit attendre un document HTML.

Vient ensuite le corps de la réponse (le document lui-même), envoyé via Response.write. Cette méthode peut être appelée plusieurs fois si vous souhaitez envoyer la réponse par morceaux, par exemple en diffusant les données en continu dès leur arrivée. Enfin, Response.end signale la fin de la réponse.

L'appel de server.listen amène le serveur à écouter les requêtes sur le port 8000. Par conséquent, vous devez accéder à localhost:8000 dans votre navigateur, et pas seulement à localhost (où le port par défaut sera 80).

Pour arrêter un script Node qui ne se termine pas automatiquement car il attend d'autres événements (dans ce cas, des connexions), vous devez appuyer sur Ctrl-C.

Un vrai serveur Web fait bien plus que ce qui est décrit dans l’exemple. Il examine la méthode de requête (la propriété de la méthode) pour comprendre quelle action le client tente d'effectuer, et l'URL de la requête pour comprendre sur quelle ressource cette action doit être effectuée. Ensuite, vous verrez une version plus avancée du serveur.

Pour créer un client HTTP, nous pouvons utiliser la fonction du module de requête « http ».

Var http = require("http"); var request = http.request(( nom d'hôte : "eloquentjavascript.net", chemin : "/20_node.html", méthode : "GET", en-têtes : (Accepter : "text/html") ), fonction(réponse) ( console .log("Le service a répondu avec du code ", réponse.statusCode); )); request.end();

Le premier argument de requête configure la requête, indiquant à Node avec quel serveur nous communiquerons, quel chemin la requête empruntera, quelle méthode utiliser, etc. La seconde est la fonction. qui devra être appelé à la fin de la demande. Un objet de réponse lui est transmis, qui contient toutes les informations sur la réponse, par exemple le code d'état.

Comme l'objet de réponse du serveur, l'objet renvoyé par la requête permet de transmettre des données avec la méthode write et de terminer la requête avec la méthode end. L'exemple n'utilise pas l'écriture car les requêtes GET ne doivent pas contenir de données dans le corps.

Pour les requêtes de sécurisation des URL (HTTPS), Node propose le module https, qui possède sa propre fonction de requête similaire à http.request.

Ruisseaux

Nous avons vu deux exemples de flux dans les exemples HTTP : l'objet de réponse, dans lequel le serveur peut écrire, et l'objet de requête, qui est renvoyé par http.request.

Les flux inscriptibles sont un concept populaire dans les interfaces Node. Tous les threads ont une méthode d'écriture, à laquelle peut être transmise une chaîne ou un objet Buffer. La méthode end ferme le flux et s'il y a un argument, elle imprimera une donnée avant de fermer. Les deux méthodes peuvent recevoir une fonction de rappel via un argument supplémentaire, qu'elles appelleront lorsque l'enregistrement sera terminé ou que le flux sera fermé.

Il est possible de créer un flux pointant vers un fichier grâce à la fonction fs.createWriteStream. Vous pouvez ensuite utiliser la méthode write pour écrire dans le fichier par morceaux plutôt que dans son ensemble, comme dans fs.writeFile.

Les flux lisibles seront un peu plus compliqués. La variable de requête transmise à la fonction de rappel dans le serveur HTTP et la variable de réponse transmise dans le client HTTP sont des flux lisibles. (Le serveur lit la demande puis écrit les réponses, et le client écrit la demande et lit la réponse). La lecture d'un flux s'effectue via des gestionnaires d'événements et non via des méthodes.

Les objets qui créent des événements dans Node ont une méthode on, similaire à la méthode addEventListener du navigateur. Vous lui donnez un nom d'événement et une fonction, et il enregistre cette fonction afin qu'elle soit appelée immédiatement lorsque l'événement se produit.

Les flux lisibles ont des événements « données » et « fin ». Le premier se produit lorsque les données arrivent, le second se produit à la fin. Ce modèle convient au streaming de données qui peuvent être traitées immédiatement, même si l'intégralité du document n'est pas reçue. Le fichier peut être lu sous forme de flux via fs.createReadStream.

Le code suivant crée un serveur qui lit les corps de la requête et les renvoie sous forme de flux de texte en majuscules.

Var http = require("http"); http.createServer(fonction(requête, réponse) (response.writeHead(200, ("Content-Type": "text/plain")); request.on("données", fonction(chunk) (response.write(chunk .toString().toUpperCase()); )); request.on("end", function() ( réponse.end(); )); )).listen(8000);

La variable chunk transmise au gestionnaire de données sera un Buffer binaire, qui peut être converti en chaîne en appelant sa méthode toString, qui la décode à partir de l'encodage par défaut (UTF-8).

Le code suivant, lorsqu'il est exécuté simultanément avec le serveur, enverra une requête au serveur et imprimera la réponse reçue :

Var http = require("http"); var request = http.request(( nom d'hôte : "localhost", port : 8000, méthode : "POST"), function(response) ( réponse.on("data", function(chunk) ( process.stdout.write(chunk .toString()); )); )); request.end("Bonjour le serveur");

L'exemple écrit dans process.stdout (la sortie standard du processus, qui est un flux inscriptible) plutôt que dans console.log. Nous ne pouvons pas utiliser console.log car il ajoute un saut de ligne supplémentaire après chaque morceau de code - ce n'est pas nécessaire ici.

Serveur de fichiers simple

Combinons nos nouvelles connaissances sur les serveurs HTTP et l'utilisation du système de fichiers, et construisons un pont entre eux : un serveur HTTP qui fournit un accès à distance aux fichiers. Il existe de nombreux cas d’utilisation d’un tel serveur. Il permet aux applications Web de stocker et de partager des données, ou peut donner à un groupe de personnes l'accès à un ensemble de fichiers.

Lorsque nous traitons des fichiers comme des ressources HTTP, les méthodes GET, PUT et DELETE peuvent être utilisées pour lire, écrire et supprimer des fichiers. Nous interpréterons le chemin dans la requête comme le chemin d'accès au fichier.

Nous n'avons pas besoin d'exposer l'intégralité du système de fichiers, nous interpréterons donc ces chemins comme relatifs au répertoire racine, et ce sera le répertoire de lancement du script. Si je démarre le serveur depuis /home/marijn/public/ (ou C:\Users\marijn\public\ sous Windows), alors une requête vers /file.txt doit pointer vers /home/marijn/public/file.txt ( ou C :\Users\marijn\public\file.txt).

Nous allons construire le programme progressivement, en utilisant l'objet méthodes pour stocker les fonctions qui gèrent différentes méthodes HTTP.

Var http = require("http"), fs = require("fs"); méthodes var = Object.create(null); http.createServer(fonction(requête, réponse) (fonction répondre(code, corps, type) (if (!type) type = "text/plain"; réponse.writeHead(code, ("Content-Type": type)) ; if (body && body.pipe) body.pipe(response); else réponse.end(body); ) if (request.method dans les méthodes) méthodes(urlToPath(request.url), répondre, demande); sinon répondre( 405, "Méthode " + request.method + " non autorisé. "); )).listen(8000);

Ce code démarrera le serveur en renvoyant des erreurs 405 - ce code est utilisé pour indiquer que la méthode demandée n'est pas prise en charge par le serveur.

La fonction de réponse est transmise aux fonctions qui gèrent différentes méthodes et agit comme un rappel pour terminer la requête. Il accepte un code d'état HTTP, un corps et éventuellement un type de contenu. Si le corps transmis est un flux lisible, il aura une méthode pipe utilisée pour transmettre un flux lisible à un flux inscriptible. Sinon, on suppose qu'il s'agit soit d'une valeur nulle (le corps est vide), soit d'une chaîne, puis elle est transmise directement à la méthode de réponse de fin.

Pour obtenir le chemin d'une URL dans une requête, la fonction urlToPath utilise le module « url » intégré de Node pour analyser l'URL. Il prend un nom de chemin, quelque chose comme /file.txt, décode pour supprimer %20 codes d'échappement et insère un point de début pour obtenir le chemin relatif au répertoire actuel.

Pensez-vous que la fonction urlToPath n'est pas sûre ? Tu as raison. Nous reviendrons sur cette question dans les exercices.

Nous allons concevoir la méthode GET pour renvoyer une liste de fichiers lors de la lecture d'un répertoire, et le contenu d'un fichier lors de la lecture d'un fichier.

La vraie question est de savoir quel type d’en-tête Content-Type devons-nous renvoyer lors de la lecture d’un fichier. Puisqu’un fichier peut contenir n’importe quoi, le serveur ne peut pas simplement renvoyer le même type pour tout le monde. Mais le NPM peut y contribuer. Le module MIME (les indicateurs de type de contenu de fichier comme text/plain sont également appelés types MIME) connaît le type correct pour un grand nombre d'extensions de fichiers.

En exécutant la commande npm suivante dans le répertoire où réside le script serveur, vous pouvez utiliser require("mime") pour interroger la bibliothèque de types.

$ npm installer mime npm http GET https://registry.npmjs.org/mime npm http 304 https://registry.npmjs.org/mime [email protégé] node_modules/mime

Lorsque le fichier demandé n'existe pas, le code d'erreur correct dans ce cas est 404. Nous utiliserons fs.stat pour renvoyer les informations du fichier afin de savoir si un tel fichier existe et s'il s'agit d'un répertoire.

Methods.GET = function(chemin, répondre) ( fs.stat(chemin, fonction(erreur, stats) (if (erreur && error.code == "ENOENT") répondre(404, "Fichier introuvable"); sinon si (erreur) répondre (500, erreur.toString()); sinon si (stats.isDirectory()) fs.readdir(chemin, fonction (erreur, fichiers) ( si (erreur) répondre(500, erreur.toString()) ; else apply(200, files.join("\n")); )); else apply(200, fs.createReadStream(path), require("mime").lookup(path)); )); );

Étant donné que les requêtes sur le disque prennent du temps, fs.stat s'exécute de manière asynchrone. Lorsque le fichier n'existe pas, fs.stat transmettra un objet d'erreur avec la propriété de code "ENOENT" à la fonction de rappel. Ce serait formidable si Node définissait différents types d'erreurs pour différentes erreurs, mais ce n'est pas le cas. Au lieu de cela, il crache des codes confus de style Unix.

Nous émettrons toutes les erreurs inattendues avec le code 500, indiquant qu'il y a un problème sur le serveur - par opposition aux codes commençant par 4, qui indiquent un problème avec la requête. Dans certaines situations, cela ne sera pas tout à fait précis, mais pour un petit exemple de programme, cela suffira.

L'objet stats renvoyé par fs.stat nous dit tout sur le fichier. Par exemple, size est la taille du fichier, mtime est la date de modification. Ici, nous devons savoir s'il s'agit d'un répertoire ou d'un fichier normal - la méthode isDirectory nous le dira.

Pour lire une liste de fichiers dans un répertoire, nous utilisons fs.readdir, et via un autre rappel, nous la renvoyons à l'utilisateur. Pour les fichiers normaux, nous créons un flux lisible via fs.createReadStream et le transmettons dans la réponse, ainsi que le type de contenu produit par le module MIME pour ce fichier.

Le code de gestion DELETE sera plus simple :

Methods.DELETE = function(chemin, répondre) ( fs.stat(chemin, fonction(erreur, statistiques) ( if (erreur && error.code == "ENOENT") répondre(204); sinon si (erreur) répondre(500 , error.toString()); sinon si (stats.isDirectory()) fs.rmdir(chemin, répondErrorOrNothing(répondre)); sinon fs.unlink(chemin, répondErrorOrNothing(répondre)); )); );

Vous vous demandez peut-être pourquoi essayer de supprimer un fichier qui n'existe pas renvoie un statut 204 au lieu d'une erreur. On peut dire que lorsque vous essayez de supprimer un fichier inexistant, puisque le fichier n'est plus là, la requête a déjà été exécutée. La norme HTTP encourage les utilisateurs à faire des requêtes idempotentes, c'est-à-dire des requêtes dans lesquelles répéter plusieurs fois la même action ne produit pas de résultats différents.

Fonction répondErrorOrNothing(répondre) ( return function(erreur) ( if (erreur) répond(500, erreur.toString()); sinon répond(204); ); )

Lorsque la réponse HTTP ne contient aucune donnée, vous pouvez utiliser le code d'état 204 (« aucun contenu »). Puisque nous devons fournir des fonctions de rappel qui signalent des erreurs ou renvoient une réponse 204 dans diverses situations, j'ai écrit une fonction spéciale responsErrorOrNothing qui crée un tel rappel.

Voici le gestionnaire de requêtes PUT :

Methods.PUT = function(chemin, réponse, demande) ( var outStream = fs.createWriteStream(chemin); outStream.on("erreur", fonction(erreur) ( répondre(500, erreur.toString()); )); outStream.on("finish", function() (response(204); )); request.pipe(outStream); );

Ici, nous n'avons pas besoin de vérifier l'existence du fichier - s'il existe, nous l'écraserons simplement. Encore une fois, nous utilisons pipe pour transférer des données d'un flux de lecture vers un flux d'écriture, dans notre cas d'une requête vers un fichier. Si le thread ne peut pas être créé, un événement « erreur » est généré, que nous signalons dans la réponse. Lorsque les données sont transférées avec succès, le tuyau ferme les deux flux, provoquant le déclenchement de l'événement « fin ». Et après cela, nous pouvons signaler le succès avec le code 204.

Le script complet du serveur est ici : eloquentjavascript.net/code/file_server.js. Il peut être téléchargé et exécuté via Node. Bien entendu, il peut être modifié et complété pour résoudre des exercices ou des expériences.

L'utilitaire de ligne de commande curl, disponible publiquement sur les systèmes Unix, peut être utilisé pour créer des requêtes HTTP. L'extrait suivant teste notre serveur. –X est utilisé pour spécifier la méthode de requête et –d est utilisé pour inclure le corps de la requête.

$ curl http://localhost:8000/file.txt Fichier introuvable $ curl -X PUT -d bonjour http://localhost:8000/file.txt $ curl http://localhost:8000/file.txt bonjour $ curl -X DELETE http://localhost:8000/file.txt $ curl http://localhost:8000/file.txt Fichier introuvable

La première requête adressée à file.txt échoue car le fichier n'existe pas encore. La requête PUT crée le fichier, et voilà, la requête suivante le récupère avec succès. Après l'avoir supprimé via DELETE, le fichier est à nouveau manquant.

Traitement des erreurs

Il existe six endroits dans le code du serveur de fichiers où nous redirigeons les exceptions lorsque nous ne savons pas comment gérer les erreurs. Étant donné que les exceptions ne sont pas automatiquement transmises aux fonctions de rappel, mais leur sont transmises sous forme d'arguments, elles doivent être traitées individuellement à chaque fois. Cela annule l’avantage de la gestion des exceptions, à savoir la possibilité de gérer les erreurs de manière centralisée.

Que se passe-t-il lorsque quelque chose lève une exception dans le système ? Nous n'utilisons pas de blocs try, il sera donc passé tout en haut de la pile d'appels. Dans Node, cela amène le programme à se terminer et à imprimer les informations d'exception (avec une trace de pile) sur la sortie standard.

Par conséquent, notre serveur plantera lorsqu'il y aura des problèmes dans le code - par opposition aux problèmes d'asynchronie, qui seront passés en arguments à la fonction d'appel. Si nous devons gérer toutes les exceptions qui se produisent lors du traitement d'une requête afin d'envoyer une réponse avec précision, nous devons ajouter des blocs try/catch dans chaque rappel.

C'est mauvais. De nombreux programmes Node sont écrits pour utiliser le moins de gestion d'exceptions possible, ce qui implique que si une exception se produit, le programme ne peut pas la gérer et doit donc planter.

Une autre approche consiste à utiliser les promesses, décrites au chapitre 17. Elles détectent les exceptions levées par les fonctions de rappel et les transmettent comme des erreurs. Dans Node, vous pouvez charger la bibliothèque de promesses et l'utiliser pour gérer les appels asynchrones. Peu de bibliothèques Node intègrent des promesses, mais elles sont généralement assez simples à envelopper. L'excellent module «promise» de NPM contient une fonction appelée denodeify, qui prend une fonction asynchrone comme fs.readFile et la convertit en une fonction qui renvoie une promesse.

Var Promesse = require("promesse"); var fs = require("fs"); var readFile = Promise.denodeify(fs.readFile); readFile("file.txt", "utf8").then(function(content) ( console.log("Le fichier contenait : " + content); ), function(error) ( console.log("Échec de la lecture du fichier : " + erreur); ));

À titre de comparaison, j'ai écrit une autre version d'un serveur de fichiers en utilisant des promesses, disponibles sur eloquentjavascript.net/code/file_server_promises.js. C'est plus propre car les fonctions peuvent désormais renvoyer des résultats plutôt que d'attribuer des rappels, et les exceptions sont transmises implicitement.

Je vais en citer quelques lignes pour démontrer la différence de styles.

L'objet fsp utilisé dans le code contient des variantes des fonctions fs avec des promesses enveloppées à l'aide de Promise.denodeify. L'objet renvoyé par le gestionnaire de méthode, avec les propriétés code et body, devient le résultat final de la chaîne de promesse et est utilisé pour déterminer la réponse à envoyer au client.

Methods.GET = function(path) ( return inspectPath(path).then(function(stats) ( if (!stats) // N'existe pas return (code : 404, corps : "Fichier introuvable"); sinon if ( stats.isDirectory()) renvoie fsp.readdir(path).then(function(files) ( return (code : 200, body : files.join("\n")); )); sinon return (code : 200, tapez : require("mime").lookup(path), body: fs.createReadStream(path)); )); ); function inspectPath(path) ( return fsp.stat(path).then(null, function(error) ( if (error.code == "ENOENT") renvoie null; sinon renvoie une erreur; )); )

La fonction inspectPath est un simple wrapper autour de fs.stat qui gère le cas où un fichier est introuvable. Dans ce cas, nous remplaçons l’erreur par success renvoyant null. Toutes les autres erreurs peuvent être transmises. Lorsque la promesse renvoyée par ces gestionnaires est rompue, le serveur répond avec le code 500.

Conclusion

Node est un système simple et efficace qui vous permet d'exécuter JavaScript en dehors du navigateur. Il a été initialement conçu pour fonctionner sur un réseau, pour jouer le rôle de nœud dans le réseau. Mais cela permet de faire beaucoup de choses, et si vous aimez programmer en JavaScript, automatiser les tâches quotidiennes avec Node fonctionne très bien.

NPM fournit des bibliothèques pour tout ce à quoi vous pouvez penser (et même certaines choses auxquelles vous ne pensez pas), et il vous permet de les télécharger et de les installer avec une simple commande. Node est également livré avec un ensemble de modules intégrés, notamment « fs » pour travailler avec le système de fichiers et « http » pour exécuter des serveurs HTTP et effectuer des requêtes HTTP.

Toutes les entrées et sorties dans Node sont effectuées de manière asynchrone, sauf si vous utilisez une variante explicitement synchrone de la fonction, telle que fs.readFileSync. Vous fournissez des fonctions de rappel et Node les appelle au moment approprié lorsque les opérations d'E/S sont terminées.

Des exercices

Et encore une fois d'accord sur le contenu
Au chapitre 17, le premier exercice consistait à créer des requêtes vers eloquentjavascript.net/author qui demandaient différents types de contenu en passant différents en-têtes Accept.

Répétez l'opération en utilisant la fonction http.request de Node. Demandez au moins les types text/plain, text/html et application/json. N'oubliez pas que les en-têtes de requête peuvent être transmis en tant qu'objet dans la propriété headers, le premier argument de http.request.

Imprimez le contenu de chaque réponse.

Réparer les fuites

Pour simplifier l'accès aux fichiers, j'ai laissé le serveur en marche sur mon ordinateur, dans le répertoire /home/marijn/public. Un jour, j'ai découvert que quelqu'un avait accès à tous mes mots de passe que j'avais stockés dans le navigateur. Ce qui s'est passé?

Si cela n'est pas clair pour vous, souvenez-vous de la fonction urlToPath, qui a été définie comme ceci :

Fonction urlToPath(url) ( var path = require("url").parse(url).pathname; return "." + decodeURIComponent(path); )

Rappelons maintenant que les chemins passés à la fonction « fs » peuvent être relatifs. Ils peuvent contenir un chemin « ../ » vers le répertoire principal. Que se passe-t-il si le client envoie des requêtes à des URL telles que les suivantes :

mon nom d'hôte :8000/../.config/config/google-chrome/Default/Web%20Data
mon nom d'hôte :8000/../.ssh/id_dsa
mon nom d'hôte :8000/../../../etc/passwd

Modifiez la fonction urlToPath pour résoudre ce problème. Veuillez noter que sous Windows, Node autorise à la fois les barres obliques inverses et les barres obliques inverses pour spécifier les chemins.

Méditez également sur le fait qu’une fois que vous exposez un système rudimentaire à Internet, les bogues du système peuvent être utilisés contre vous et votre ordinateur.

Création de répertoires
Bien que la méthode DELETE fonctionne également lors de la suppression de répertoires (via fs.rmdir), le serveur ne propose pas encore la possibilité de créer des répertoires.

Ajoutez la prise en charge de la méthode MKCOL, qui devrait créer un répertoire via fs.mkdir. MKCOL n'est pas une méthode HTTP de base, mais elle existe dans ce but précis dans la norme WebDAV, qui contient des extensions à HTTP pour lui permettre d'être utilisée pour écrire des ressources plutôt que de simplement les lire.

Lieu public sur le Web
Étant donné que le serveur de fichiers sert tous les fichiers et renvoie même l'en-tête Content-Type correct, il peut être utilisé pour servir un site Web. Puisqu'il permet à quiconque de supprimer et de remplacer des fichiers, ce serait un site intéressant - un site qui pourrait être modifié, corrompu et supprimé par toute personne pouvant créer une requête HTTP valide. Mais ce serait toujours un site Web.

Écrivez une page HTML simple avec un simple fichier JavaScript. Placez-les dans un répertoire servi par le serveur et ouvrez-les dans un navigateur.

Ensuite, comme exercice avancé, combinez tout ce que vous avez appris dans le livre pour créer une interface plus conviviale permettant de modifier un site Web à partir du site lui-même.

Utilisez un formulaire HTML (Chapitre 18) pour éditer les fichiers qui composent le site, permettant à l'utilisateur de les mettre à jour sur le serveur via des requêtes HTTP, comme décrit au Chapitre 17.

Commencez avec un fichier que vous pouvez modifier. Faites ensuite en sorte que vous puissiez sélectionner le fichier à modifier. Profitez du fait que notre serveur de fichiers renvoie des listes de fichiers à la demande d'un répertoire.

Ne modifiez pas les fichiers directement dans le code du serveur de fichiers. Si vous faites une erreur, vous corromprez probablement ces fichiers. Travaillez dans un répertoire non accessible de l'extérieur et copiez-les là après les tests.

Si votre ordinateur se connecte directement à Internet, sans pare-feu, routeur ou autre appareil, vous pouvez inviter un ami sur votre site. Pour vérifier, allez sur whatismyip.com, copiez l'adresse IP dans la barre d'adresse et ajoutez : 8000 pour sélectionner le port souhaité. Si vous êtes sur votre site, il est accessible à tous.

Dans un nœud, vous pouvez définir des variables globales via un objet "global" ou "GLOBAL":

GLOBAL._ = require("trait de soulignement"); // mais vous ne "devriez" pas faire ça ! (voir note ci-dessous)

ou plus utile...

GLOBAL.window = GLOBAL ; // comme dans le navigateur

À partir de la source du nœud, vous pouvez voir qu'il s'agit d'alias les uns pour les autres :

Node-v0.6.6/src/node.js:28:global = this; 128 : global.GLOBAL = global ;

Dans le code ci-dessus, « ceci » est le contexte global. Avec le module commonJS (que le nœud utilise), cet "objet" à l'intérieur du module (c'est-à-dire "votre code") n'est PAS le contexte global. Pour preuve, voyez ci-dessous où je crache "cet" objet, puis l'objet géant "GLOBAL".

Console.log("\nCECI :"); console.log(this); console.log("\nGLOBAL:"); console.log(global); /* les sorties ... CE: {} MONDIAL: ( ArrayBuffer : , Int8Array : ( BYTES_PER_ELEMENT : 1 ), Uint8Array : ( BYTES_PER_ELEMENT : 1 ), Int16Array : ( BYTES_PER_ELEMENT : 2 ), Uint16Array : ( BYTES_PER_ELEMENT : 2 ), Int32Array : ( BYTES_PER_ELEMENT : 4 ), Uint32Array : ( BYTES_PER_ELEMENT : 4 ), Float32Array : ( BYTES_PER_ELEMENT : 4 ), Float64Array : ( BYTES_PER_ELEMENT : 8 ), DataView : , global : , processus : ( EventEmitter : , titre : "node", assert : , version : "v0.6.5", _tickCallback : , moduleLoadList : [ "Évaluations de liaison", "Liaisons natives", "Événements NativeModule", "Tampon NativeModule", "Tampon de liaison", "Assistation NativeModule", "Utilitaire NativeModule", "Chemin NativeModule", "Module NativeModule", " NativeModule fs", "Binding fs", "Constantes de liaison", "NativeModule stream", "NativeModule console", "Binding tty_wrap", "NativeModule tty", "NativeModule net", "NativeModule timers", "Binding timer_wrap", " NativeModule _linklist" ], versions : ( nœud : "0.6.5", v8 : "3.6.6.11", ares : "1.7.5-DEV", uv : "0.6", openssl : "0.9.8n" ), nextTick : , stdout: , arch: "x64", stderr: , platform: "darwin", argv: [ "node", "/workspace/zd/zgap/darwin-js/index.js" ], stdin: , env: ( TERM_PROGRAM : "iTerm.app", "COM_GOOGLE_CHROME_FRAMEWORK_SERVICE_PROCESS/USERS/DDOPSON/LIBRARY/APPLICATION_SUPPORT/GOOGLE/CHROME_SOCKET": "/tmp/launch-nNl1vo/ServiceProcessSocket", TERM : "xterm", SHELL : "/bin/bash" , TMPDIR : "/var/folders/2h/2hQmtmXlFT4yVGtr5DBpdl9LAiQ/-Tmp-/", Apple_PubSub_Socket_Render : "/tmp/launch-9Ga0PT/Render", UTILISATEUR : "ddopson", COMMAND_MODE : "unix2003", SSH_AUTH_SOCK : "/tmp/ launch -sD905b/Listeners", __CF_USER_TEXT_ENCODING : "0x12D732E7:0:0", PATH : "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:~/bin:/usr/ X11 /bin", PWD : "/workspace/zd/zgap/darwin-js", LANG : "en_US.UTF-8", ITERM_PROFILE : "Par défaut", SHLVL : "1", COLORFGBG : "7;0", HOME : "/Users/ddopson", ITERM_SESSION_ID : "w0t0p0", LOGNAME : "ddopson", DISPLAY : "/tmp/launch-l9RQXI/org.x:0", OLDPWD : "/workspace/zd/zgap/darwin- js /external", _ : "./index.js"), openStdin : , exit : , pid : 10321, fonctionnalités : ( debug : false, uv : true, ipv6 : true, tls_npn : false, tls_sni : true, tls : true ), kill: , execPath: "/usr/local/bin/node", addListener: , _needTickCallback: , on: , removeListener: , veryExit: , chdir: , debug: , error: , cwd: , watchFile: , umask : , getuid : , unwatchFile : , mixin : , setuid : , setgid : , createChildProcess : , getgid : , hérite : , _kill : , _byteLength : , mainModule : ( id : ". ", exports : (), parent : null, nom de fichier : "/workspace/zd/zgap/darwin-js/index.js", chargé : false, sorti : false, enfants : , chemins : ), _debugProcess : , ouvert : , uptime : , memoryUsage : , uvCounters : , liaison : ), GLOBAL : , root : , Buffer : ( poolSize : 8192, isBuffer : , byteLength : , _charsWritten : 8 ), setTimeout : , setInterval : , clearTimeout : , clearInterval : , console : , fenêtre : , navigateur : () ) */

**Remarque : concernant le paramètre "GLOBAL._", en général, vous devez simplement faire var _ = require("underscore"); Oui, vous faites cela dans chaque fichier qui utilise le trait de soulignement, tout comme en Java, vous importez com.foo.bar ; Cela facilite la détermination de ce que fait votre code car les liens entre les fichiers sont « explicites ». Un peu ennuyeux, mais bon. Ceci est un sermon.

Il y a une exception à chaque règle. J'ai eu exactement un cas où je devais définir "GLOBAL._". Je créais un système pour définir des fichiers "config" qui étaient pour la plupart JSON, mais qui étaient "écrits en JS" pour ajouter un peu plus de flexibilité. Il n'y avait pas d'instructions "require" dans de tels fichiers de configuration, mais je voulais qu'ils aient accès au trait de soulignement (le système ENTIER était basé sur des traits de soulignement et des modèles de trait de soulignement), donc je définirais "GLOBAL._" avant d'évaluer "config". Alors oui, pour chaque règle, il y a une exception quelque part. Mais vous avez une bonne raison, pas seulement « J’en ai marre de taper », donc je veux rompre l’accord. »

et on m'a dit que je pouvais définir les variables sur la portée globale, en laissant var.

Cela ne fonctionne pas pour moi.

Exiger("trait de soulignement");

Ne rend pas _ disponible pour les fichiers requis. Je peux installer app.set et l'utiliser ailleurs.

Quelqu'un peut-il confirmer que cela devrait fonctionner ? Merci.

4 sur 5

Dans cet article, je parlerai des principes de base de Node.js, de ses avantages et inconvénients, et je vous montrerai comment commencer à développer. Mais avant de commencer à travailler avec Node.js, il est conseillé de comprendre la différence entre Node.js et les langages traditionnels côté serveur (PHP, Python, Ruby).

Programmation asynchrone

J'espère que vous êtes familier avec la programmation asynchrone. Quoi qu’on en dise, c’est la base à l’Ajax. Toutes les fonctions des modules principaux de Node.js sont asynchrones. Par conséquent, toutes les fonctions qui bloqueraient normalement un thread dans d’autres langages sont exécutées en arrière-plan dans Node.js. C'est la chose la plus importante pour comprendre Node.js. Par exemple, si vous lisez un fichier, une fonction doit être spécifiée qui sera exécutée une fois la lecture terminée.

Vous ferez tout !

Node.js n'est qu'un framework, donc tout le travail devra être effectué manuellement. Node.js n'a même pas de serveur HTTP par défaut ! Et c'est triste, mais Node.js impressionne par ses hautes performances d'applications Web. Un seul script gère toutes les connexions au client. Cette solution réduit considérablement la quantité de ressources utilisées dans l'application. Par exemple, voici le code d'une simple application Node.js.

Var je, une, b, c, max ;

maximum = 1 000 000 000 ;

var d = Date.now();

pour (je = 0; je< max; i++) {
une = 1234 + 5678 + je;
b = 1234 * 5678 + je ;
c = 1234 / 2 + je ;
}

console.log(Date.now() - d);

Et voici son équivalent en PHP :

$a = nul ;
$b = nul ;
$c = nul ;
$i = nul ;
$max = 1 000 000 000 ;
$start = microtime(true);
pour ($i = 0; $i< $max; $i++) {
$a = 1 234 + 5 678 + $i ;
$b = 1 234 * 5 678 + $i ;
$c = 1234 / 2 + $i ;
}
var_dump(microtime(true) - $start);

Le tableau suivant compare le temps d'exécution des deux exemples.

Les deux exemples ont été exécutés sur la ligne de commande, il n'y a donc aucun délai dans le démarrage du serveur Web. J'ai effectué chaque test 10 fois et pris le résultat moyen. PHP était plus rapide pour un petit nombre d’itérations, mais cet avantage disparaissait rapidement à mesure que le nombre d’itérations augmentait. Lorsque j'ai terminé tous les tests, PHP était 93 % plus lent que Node.js.

Node.js est rapide, mais vous devez savoir certaines choses pour l'utiliser correctement.

Modules

Node.js est construit sur une architecture modulaire : ceci est fait pour simplifier la création d'applications complexes. Les modules sont similaires aux bibliothèques en C ou aux unités en Pascal. Chaque module contient un ensemble de fonctions liées au « sujet » de ce module. Par exemple, le module http contient des fonctions spécifiques à HTTP. Node.js contient également plusieurs modules prêts à l'emploi : pour travailler avec le système de fichiers, créer des serveurs HTTP et TCP/UPD, etc.

Le module est connecté à l'aide de la fonction require() :

Var http = require("http");

Cette fonction renvoie le module spécifié. Dans l'exemple ci-dessus, le lien vers le module http est stocké dans la variable http.

La fonction prend le nom du module en entrée. Node.js vérifie ensuite le dossier node_modules dans le répertoire de l'application et y recherche un dossier appelé http. Si Node.js ne trouve pas le répertoire node_modules ou le module http dans ce répertoire, il se tournera vers le module global mis en cache. Au lieu d'un nom, vous pouvez transmettre un chemin relatif ou absolu au module à la fonction require() :

Var monModule = require("./myModule.js");

Les modules encapsulent des morceaux de code. Le code à l'intérieur du module est principalement privé. Cela signifie que les fonctions et variables déclarées dans un module ne sont disponibles que dans le module. Mais Node.js vous permet de créer des fonctions et/ou des variables publiques. L'objet exports en est responsable. Exemple:

VarPI = Math.PI ;
exports.area = fonction (r) (
renvoyer PI * r * r ;
};
exports.circumference = fonction (r) (
renvoyer 2 * PI * r ;
};

Cet exemple crée une variable PI qui ne peut être utilisée que dans un module. Les 2 fonctions suivantes créent un objet d'exportation. Ces fonctions sont disponibles en dehors du module car elles sont définies via l'objet exports. La variable PI est ainsi entièrement protégée des interférences externes. De cette façon, les fonctions d'aire et de circonférence se comporteront comme elles le devraient (en fonction de la valeur du paramètre r).

Portée mondiale

Node.js est un environnement JavaScript développé sur le moteur JavaScript V8 de Google. Il est donc nécessaire d’utiliser les meilleures pratiques de programmation côté client. Par exemple, vous devez éviter les déclarations dans la portée globale. Cependant, ce n'est pas toujours possible. Dans Node.js, il est facile de créer une variable ou une fonction globale en omettant le mot-clé var, comme ceci :

Variable globale = 1 ;
globalFunction = fonction () ( ... );

Encore une fois, les variables et fonctions globales doivent être évitées autant que possible. Alors soyez prudent : utilisez var pour déclarer des variables !

Installation

Bien entendu, avant de pouvoir écrire et exécuter des applications dans Node.js, vous devez l'installer. Vous pouvez télécharger un programme d'installation pour Windows ou OS X sur le site nodejs.org. Pour Linux, vous pouvez utiliser n'importe quel gestionnaire de packages. Pour installer Node.js, vous devez ouvrir la ligne de commande et saisir :

Sudo apt-get mise à jour
sudo apt-get nœud d'installation

Mise à jour des aptitudes Sudo
Nœud d'installation sudo aptitude

Node.js est disponible dans les référentiels sid ; vous pouvez les ajouter à la liste des codes sources :

Sudo echo deb http://ftp.us.debian.org/debian/ sid main > /etc/apt/sources.list.d/sid.list

L'installation de packages sid sur des systèmes plus anciens peut endommager votre système. Par conséquent, après l'installation, il est conseillé de supprimer /etc/apt/sources.list.d/sid.list

Installation de nouveaux modules

Node.js dispose d'un gestionnaire de packages appelé Node Package Manager (NPM). NPM est installé automatiquement avec Node.js et peut être utilisé pour installer de nouveaux modules. Pour installer un nouveau module, vous devez ouvrir la ligne de commande, accéder au dossier souhaité et exécuter la commande suivante :

Npm installer nom_module

La syntaxe de cette commande est indépendante du système d'exploitation. La commande installera le module spécifié à la place de module_name.

Bonjour le monde

La première application que j'écrirai dans Node.js sera « Hello World ! ». Pour ce faire, je vais créer un fichier appelé hello.js et ajouter le code suivant :

Console.log("Bonjour tout le monde !");

Pour exécuter le script, vous devez ouvrir la ligne de commande, accéder au dossier contenant le fichier hello.js et exécuter la commande suivante :

Nœud bonjour.js

La console affichera « Hello World ! »

serveur HTTP

Je vais maintenant rendre l'application plus complexe, mais pas aussi complexe qu'on pourrait le penser). Le code contient des commentaires.

// connecte le module http.
var http = require("http");

// Créez un serveur. La fonction est passée en paramètre à chaque requête.
// la variable de requête contient tous les paramètres de requête.
// la variable de réponse permet de spécifier ce qu'il faut faire lors de l'envoi d'une réponse au client

// Cet événement se produit lorsque le client a envoyé des données et attend une réponse
// Écrit les en-têtes en réponse.
// 200 est le code d'état HTTP (200 signifie ok)
// Le deuxième paramètre est un objet qui contient les champs d'en-tête
// J'envoie du texte brut en utilisant un type de contenu text/plain
réponse.writeHead(200, (
"Content-Type": "texte/plain"
});
// Envoyer des données
réponse.end("Bonjour HTTP!");
});
// Écoutez le port 8080.
)).écouter(8080);

Ceci est un exemple très simple. En fait, vous pouvez envoyer beaucoup plus de données au client en utilisant la méthode Response.write(), mais elle doit être appelée avant la méthode Response.end(). J'ai enregistré ce code dans un fichier http.js et je l'ai entré dans la console :

Nœud http.js

Ensuite, j'ai ouvert le navigateur et je suis allé sur http://localhost:8080. La page affiche « Bonjour HTTP ! »

Traitement des paramètres d'URL

Comme je l'ai mentionné plus tôt, nous devons tout faire nous-mêmes dans Node.js, y compris analyser les arguments de la requête. Cependant, ce n’est pas si difficile. Et dans l'exemple suivant, je vais démontrer ceci :

// Connectez le module http,
var http = require("http"),
// et un module url qui aidera lors de l'analyse des paramètres de la requête
url = exiger("url");

// Créez un serveur.
http.createServer(fonction (demande, réponse) (
// Ajout d'un gestionnaire d'événements.
request.on("fin", fonction () (
// Analyse la demande d'arguments et les stocke dans la variable _get.
// Cette fonction analyse l'URL et renvoie un objet.
var _get = url.parse(request.url, true).query;
// Écrit les en-têtes en réponse.
réponse.writeHead(200, (
"Content-Type": "texte/plain"
});
// Envoie les données et complète la réponse.
réponse.end("Voici vos données : " + _get["data"]);
});
// Ecoute sur le port 8080.
)).écouter(8080);

Ce code utilise la méthode parse() du module url, qui est le module principal de Node.js pour analyser une URL en un objet. L'objet renvoyé possède une propriété de requête qui récupère les paramètres d'URL. J'ai enregistré ce code dans un fichier get.js et exécuté la commande suivante :

Nœud get.js

Ensuite, j'ai ouvert la page http://localhost:8080/?data=put_some_text_here dans le navigateur.

Lire et écrire des fichiers

Il existe un module fs pour travailler avec des fichiers dans Node.js. Ce module dispose des méthodes fs.readFile() et fs.writeFile() pour lire et écrire des fichiers. Je vous en dirai plus après avoir regardé l'exemple :

// Connectez le module http,
var http = require("http"),
// et module fs
fs = exiger("fs");

// Créez un serveur http.
http.createServer(fonction (demande, réponse) (
// Ajout d'un gestionnaire d'événements.
request.on("fin", fonction () (
// Lire le fichier
// Écrit les en-têtes.
réponse.writeHead(200, (
"Content-Type": "texte/plain"
});
//Augmente le nombre obtenu à partir du fichier.
données = parseInt(données) + 1 ;
// Écrit un nouveau numéro dans le fichier.

);
});
// Écoute le port 8080
)).écouter(8080);

J'ai enregistré ce code dans un fichier files.js. Avant d'exécuter ce script, vous devez créer un fichier nommé test.txt dans le répertoire contenant files.js.

Ce code démontre le fonctionnement des méthodes fs.readFile() et fs.writeFile(). Chaque fois que le serveur reçoit une requête, le script lit un numéro dans le fichier, l'incrémente et écrit un nouveau numéro dans le même fichier. La méthode fs.readFile() prend 3 arguments : le nom du fichier à lire, le l'encodage attendu et la fonction à appeler.

Écrire dans un fichier est beaucoup plus simple. Vous ne devez vous attendre à aucun résultat, même si dans une application réelle, vous devez vérifier les erreurs. La méthode fs.writeFile() prend le nom du fichier et écrit les données comme arguments. Cette méthode peut également prendre un 3ème et un 4ème argument facultatif pour spécifier la fonction d'encodage et de rappel.

J'ai exécuté le script avec la commande :

Fichiers de nœud.js

Ensuite, j'ai ouvert http://localhost:8080 dans le navigateur et je l'ai redémarré plusieurs fois. Il peut sembler qu'il y ait une erreur dans le code, car... le nombre a augmenté de 2. Ce n'est pas une erreur car en réalité 2 demandes ont été envoyées. La première requête a été automatiquement effectuée par le navigateur lorsqu'il a demandé favicon.ico et la deuxième requête était http://localhost:8080.

Bien qu'il ne s'agisse pas techniquement d'un bug, le comportement de ce script n'est pas évident. J'ai donc ajouté un correctif qui vérifie l'URL. Voici le code corrigé :

// Connectez le module http,
var http = require("http"),
// et module fs
fs = exiger("fs");

// Créez un serveur http.
http.createServer(fonction (demande, réponse) (
// Ajout d'un gestionnaire d'événements.
request.on("fin", fonction () (
// Vérifiez la demande /
if (request.url == "/") (
// Lit le fichier.
fs.readFile("test.txt", "utf-8", fonction (erreur, données) (
// Écrit les en-têtes.
réponse.writeHead(200, (
"Content-Type": "texte/plain"
});
// Augmente le nombre obtenu à partir du fichier.
données = parseInt(données) + 1 ;
// Écrivez le nombre augmenté dans le fichier.
fs.writeFile("test.txt", données);
// Écrivez un joli message en réponse.
réponse.end("Cette page a été actualisée " + données + " fois ! ");
});
) autre (
// Fichier introuvable
réponse.writeHead(404);
// et terminez la requête sans envoyer de données.
réponse.end();
}
});
// Écoutez le port 8080.
)).écouter(8080);

Le script fonctionne désormais comme prévu.

Accès à MySQL

Les technologies de serveur traditionnelles disposent de moyens intégrés pour connecter et interroger une base de données. Pour Node.js, vous devez installer une bibliothèque spéciale. J'ai choisi le node-mysql le plus stable et le plus facile à utiliser. Le module complet s'appelle [email protégé](après @ vient la version). Pour installer ce module, j'ai ouvert la console, je suis allé dans le répertoire où sont stockés les scripts et j'ai exécuté la commande suivante :

Installation de Npm [email protégé]

Cette commande téléchargera et installera le module et créera un dossier node_modules dans le répertoire actuel. Ensuite, j'ai écrit un exemple d'utilisation de ce module :

// Connectez le module http,
var http = require("http"),
// et module mysql.
mysql = require("mysql");

// Crée une connexion.
// Les paramètres par défaut doivent être modifiés en fonction des paramètres MySQL.
var connexion = mysql.createConnection((
utilisateur : "root",
mot de passe: "",
base de données : "nom_base de données"
});

// Créez un serveur http.
http.createServer(fonction (demande, réponse) (
// Ajout d'un gestionnaire d'événements.
request.on("fin", fonction () (
// Requête à la base de données.
connection.query("SELECT * FROM your_table;", fonction (erreur, lignes, champs) (
réponse.writeHead(200, (
"Content-Type": "x-application/json"
});
// Envoie les données au format json.
// Les chaînes variables contiennent le résultat de la requête.
réponse.end(JSON.stringify(rows));
});
});
// Écoutez le port 8080.
)).écouter(8080);

Une requête vers la base de données est simple : vous devez écrire la requête elle-même et une fonction de rappel dans la méthode de requête. Dans une application réelle, vous devez d'abord vérifier s'il y a eu des erreurs (le paramètre d'erreur ne sera pas défini s'il y a eu des erreurs) et la réponse dépend du fait que la requête a été complétée ou non. Notez également que j'ai défini le Content-Type sur x-application/json, cela indique que le type MIME est bien json. Le paramètre rows contient le résultat de la requête, que j'ai facilement converti en structure JSON à l'aide de la méthode JSON.stringify().

J'ai enregistré ce code dans un fichier mysql.js et exécuté la commande :

Nœud mysql.js

Ensuite, je suis allé sur http://localhost:8080 dans le navigateur et le navigateur m'a proposé de télécharger le fichier au format JSON.

Conclusion

Bien que dans Node.js, vous deviez faire beaucoup de choses manuellement, tout cela se révèle payant par la rapidité et la fiabilité de vos applications. Si vous ne souhaitez pas développer des applications à bas niveau, vous pouvez toujours utiliser un framework pour faciliter la tâche. Par exemple Express.

Node.js est une technologie prometteuse et un excellent choix pour les applications à forte charge. Cela a été prouvé par des sociétés telles que Microsoft, eBay et Yahoo. Si vous n'êtes pas sûr du choix d'hébergement pour votre site Web ou votre application, vous pouvez toujours utiliser une solution VPS bon marché ou divers services cloud tels que Microsoft, Azure et Amazon EC2.