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
Besoin d'interactions fines avec le serveur ⇒ XMLHttpRequest
Quel impact ?
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
Avantages :
$ 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]
//Fichier hello.js
function helloWorld() {
console.log("Hello, World!");
}
helloWorld();
Dans un terminal :
$ node hello.js
Hello, World!
⇒ Un symbole global (fonction, variable, constante, classe, …) n'est pas visible par défaut dans les autres fichiers.
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:
Classes (au sens Java ou C++) :
Namespaces (au sens C++) :
Headers (.h de C ou C++)
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
const hello = require ("./hello.js");
hello.helloWorld();
console.log(hello.message.length);
hello.print n'est pas visible à l'extérieur.
Avantages :
//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
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.
Bien d'autres modules utilitaires. Pas beaucoup de structures de données.
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 ?
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");
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é
//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
On veut créer un petit serveur Web minimal :
Il manque encore des morceaux :