Programmation Web Avancée

Cours 6
nodejs logo

kn@lri.fr

Historique

Programmation Web

Côté client

Côté serveur

Problèmes d'avoir deux langages : pas de partage de code, pas de partage de compétences, infrastructure de tests séparées, différents paradigmes

Modèle classique de la programmation Web Client/Serveur

  1. Client charge la page
  2. Animations locales en JS
  3. Remplissage de formulaire
  4. Envoie d'une requête HTTP
  5. Goto 1

Besoin d'interactions fines avec le serveur ⇒ XMLHttpRequest

Quel impact ?

Code serveur classique (PHP ou Java/JSP)

Exemple : dépôt de fichier et bare de chargement côté client

⇒ problème de performances

Constat fait par Ryan Dahl en 2009 ⇒ création de Nodejs

Principes de Nodejs

Avantages :

Présentation

L'interpréteur nodejs (console)

$ node > console.log("Hello, world !"); Hello, world! undefined > let answer = 42; undefined > 1 + answer; 43

Fonctionne comme la console d'un navigateur, affiche le résultat de l'expression

Possibilité de compléter avec [TAB]

L'interpréteur nodejs (script)

//Fichier hello.js function helloWorld() { console.log("Hello, World!"); } helloWorld();

Dans un terminal :

$ node hello.js Hello, World!

Différence entre la console et le mode programme

⇒ Un symbole global (fonction, variable, constante, classe, …) n'est pas visible par défaut dans les autres fichiers.

Modules en Nodejs

Qu'est-ce qu'un module ? (en général)

Une portion close de code regroupant des concepts (fonction, type, constante) reliés.
Un module fournit :

A priori, un module n'est pas extensible et n'a pas de dépendences cycliques.
Quelques langages avec modules et sans:

Choses qui ne sont pas des modules

Classes (au sens Java ou C++) :

Namespaces (au sens C++) :

Headers (.h de C ou C++)

Définition d'un module (format CommonJS)

Au sein d'un fichier hello.js :

const message = "Hello, world!"; function print(s) { console.log (s); } function helloWorld() { print (message) } module.exports.message = message; module.exports.helloWorld = helloWorld;

Dans le fichier main.js

const hello = require ("./hello.js"); hello.helloWorld(); console.log(hello.message.length);

hello.print n'est pas visible à l'extérieur.

Sémantique des modules nodejs (simplifiée)

Avantages :

Exemple d'utilisation avancée

//fichier arith.js function f (x) { … } function g (x, y) { … } function h (x, y) { … } module.exports = { neg : f, add : g, mult : h }; ------------------------------------------------ //fichier user.js const math = require ('./arith.js'); // on peut utiliser math.neg, math.add, math.mult const { neg, mult } = require ('./arith.js'); // on peut utiliser la notation générique pour // associer directement aux variables neg et mult les champs // neg et mult de l'objet renvoyé par require // ici on peut utiliser neg/mult sans préfixe

Modules de la bibliothèque standard

Pour ces derniers, on ne met pas de chemin ni d'extension

L'usage veut que l'on définisse une variable qui s'appelle comme le module

const fs = require ('fs'); const http = require ('http');

Il est aussi plus propre de définir la variable contenant le module avec const, pour empêcher une modification non voulue.

let fs = require ('fs'); const http = require ('http'); fs = 42; //ooops, fs ne contient plus un module mais un Number http = 42; //erreur, car http est const.

Quelques modules utiles

child_process
Lancement de programmes (exec, fork, …)
console
Console de débuggage (console.log, console.debug, …). Ouvert automatiquement, pas besoin de require.
dns
résolution de noms de domaines
fs
Système de fichier (ouverture de fichier, répertoires, …)
http
Serveur HTTP simple.
https
Serveur HTTPS simple.
os
Informations sur le système (nombre de CPUs, OS, …)
process
Gestion des processus (envoie de messages, kill, …)
querystring
décodage/encodage des chaînes de la forme: ?a=b&c=%20&…
timer
Expose les fonctions setTimeout et setInterval. Ouvert automatiquement.
zlib
Lecture/écriture d'archives zip

Bien d'autres modules utilitaires. Pas beaucoup de structures de données.

Synchrone/asynchrone

La plupart des fonctions « lentes » (i.e. potentiellement soumise à l'attente d'un évènement externe) sont asynchrones. Elle prennent en argument supplémentaire un callback appelé sur le résultat de la fonction.

Souvent (mais pas tout le temps) des version synchrones existent. Leur nom contient le suffixe Sync.

const fs = require ('fs'); fs.copyFile("fichier.txt", "copie.txt", (err) => { if (err) throw err; //leve une exception si err est non null console.log("Copie terminée"); }); fs.copyFileSync("fichier.txt", "copie.txt"); //leve une exception en cas d'erreur console.log("Copie terminée");

Quelle est la différence entre ces deux versions ?

Synchrone/asynchrone

La version asynchrone rend la main au runtime nodejs. Pas d'attente active, d'autres évènements peuvent êtres déclanchés pendant la copie.

La version synchrone bloque tout le runtime, jusqu'à la fin de la copie.

😱 La bibliothèque standard nodejs n'utilisait pas de promesse jusqu'à la version 11.x

C'est maintenant possible, mais les fonctions qui renvoient les promesses sont dans des sous-modules particuliers :

const fs = require ('fs/promises'); await fs.copyFile("fichier.txt", "copie.txt"); //lève une exception en cas d'erreur console.log("Copie terminée");

Modules en Javascript

Histoire des modules JS

Programmes écrit en JS côté serveur ⇒ nécessité d'un système de modules (CommonJS, dont celui de NodeJS est un successeur)

En parallèle, proposition d'autres types de modules adapté au JS dans le navigateur

2015 : EcmaScript 6, proposition d'un système de modules dans le standard

Problème : fait pour concilier JS Client et JS serveur, pas encore supporté ni finalisé

Exemple de modules ES

//fichier mod.js import * as fs from 'fs' import 'other_module' fs.copyFile(…); f (…); // définit comme defaut dans 'other_module' export function publicFun(…) { … } export default function foo() { … }

Support préliminaire dans NodeJS 8.x avec --experimental-modules

Support stable depuis NodeJS 13.x

Support dans les navigateurs depuis 2018

Démo

Démo : serveur Web

On veut créer un petit serveur Web minimal :

Nodejs …

Il manque encore des morceaux :