Formation NodeJS
Xavier Van de Woestyne - Novembre 2016Bonjour !
- Développeur à Dernier Cri
- Programmation depuis 1999
- Travail de recherche (un peu particulier)
- @xvw sur Github et Medium, @vdwxv sur Twitter
- Outils principaux: OCaml, Erlang, Elixir, F#, Ruby, JavaScript, Haskell.
Dernier Cri
Une agence d'innovation numérique
- Web (développement/UI/UX)
- Conception de produits et logiciels
- Analyse et Machine-Learning
- Consultance
- Open-Source
- Formations
- Ouvert à la communauté
Rapide tour de présentation
- Prénom et Nom
- Eventuellement âge, hobbies
- Expérience en développement
Je peux tutoyer ou vouvoyer à la convenance !
Objectifs de la formation
- Comprendre le langage JavaScript (et son intérêt)
- S'initier au développement d'application server-side avec JavaScript
- Comprendre les motifs récurrents du web moderne
Programme
Jour 1: Introduction à JavaScript
- Présentation et historique
- Tester en ligne de commande
- Eléments de syntaxe
- Programmation fonctionnelle
- Programmation orientée objets
- Gestion des erreurs
- Exercice : intrerprêter Brainfuck
- Présentation
- Eco-système (NPM, modules)
- Packager une application
Jour 2 : Fonctionnement d'un serveur web
- Principe général
- Serveurs génériques
- Application exposant un serveur
- Un premier serveur simple
- Programmation événementielle
- Les Streams
- Routage
- Descripteur de fichiers : lecture / écriture
- Exercice : un serveur de fichiers statiques
Jour 3 : Implémentations concrètes
- Express : simplification des routes
- Requêtes HTTP's
- Promesses
- SOAP
- Persistence de données
- WebSockets via SocketIO
- Exercice : utilisation des WebSockets
- Notion de processus
- Clusters et workers
- Stratégies d'ordonnancement
- Programmation concurrente et acteurs
- Implémentation manuelle de MapReduce
JavaScript historiquement
Comment il est devenu ce qu'il est...
Historiquement
- Brendan Eich, 1995
- Netscape VS Internet Explorer
- Destiné à ajouter des effets aux pages
De LiveScript à JavaScript
- LiveScript : langage serveur pour Netscape
- JavaScript : version cliente de LiveScript pour le navigateur
- Inspiré par Self et Lisp
- JScript : version de Internet Explorer (Course à la feature)
- Devenu un standard dans les navigateurs
Définition formelle de JavaScript
Le JavaScript est un langage de programmation de scripts orienté objet.
- Langage compilé : modification d'un code source dans un autre langage
-
Langage interprèté :
Lecture séquentielle du code "étape par étape".
(Peut être, pour des gains de performance, compilé "à la volée").
ECMAScript
Chaque navigateur embarque son interpréteur...
il a donc fallu normaliser JavaScript.
- Version mieux supportée : ES5
- Dernière version avancée : ES6 (ou ES2015)
- Tanspilers, Babel.
Evolution du langage
- Du DHTML a L'Ajax en passant par jQuery
- Analyse statique (Flow)
- Evolution de la norme (ES20XX) et Polyfills
- JavaScript comme un ByteCode (avant WebAssembly, Haxe, Elm, TypeScript etc.)
- JavaScript comme un langage généraliste
Syntaxe et éléments du langage
Avec ES2015 entre autre
Sommaire
- Variables
- Conditions
- Boucles
- Fonctions
- Objets et tableaux
Utiliser JavaScript en dehors du Navigateur
$ node
Pour lancer un REPL$ node fichier.js
Pour exécuter un fichier
Variables
- var : `var name = value`
- let : `let name = value`
- const : `const name = value`
respectée.
Conditions
- if/else
- Conditions ternaires
- switch/case
Boucles
- while/do while
- for
- Récursion
- Combinateurs fonctionnels
Fonctions
function name(arg1, arg2) { ... }
let name = function(arg1, arg2) { ... };
let name = (arg1, arg2) => { ... };
setTimeout(f, ms) && setInterval(f, ms)
Closure : isoler du code
(function(x) { ... })(y);
Soit une fonction sans nom exécutée tout de suite.
- Permet de scoper des variables
- Permet donc d'éviter les problèmes de passage par référence
- Permet de simuler le mot-clé "statique"
Programmation Fonctionnelle
- Lambda-calculus (1935)
- Pilliers de la programmation fonctionnelle
- Motif agréable à utiliser
Programmation orientée Objets
- Simula, Self et Smalltalk... C++, Java... PHP... JavaScript
- Tout est message
- 3 sous-paradigmes
- Réutilisabilité et morcellement de code
- Encapsulation
- Modèle complexe à utiliser avec parcimonie
- Référence des "built-in"'s objects
Tableaux
let tab = [1, 2, 3];
let tab = new Array(a, b, c, ...);
function(...args) // args devient un tableau
let tab = new Array(taille).fill(valeur_par_défaut);
tab[i] = new_value;
- Méthodes sur les tableaux
Itérer sur un tableau
for(let i = 0; i < tab.length; i++) { console.log(tab[i]); }
for(i in tab) { console.log(tab[i]); }
tab.forEach(i => console.log(i));
Combinateurs fonctionnels
forEach(fun(elt, *i, *array))
find(fun(elt, *i, *array))
filter(fun(elt, *i, *array))
findIndex(fun(elt, *i, *array))
map(fun(elt, *i, *array))
reduce(fun(acc, elt, *i, *array), accumulateur)
(ou reduceRight)some(fun(elt, *i, *array))
every(fun(elt, *i, *array))
Proposition : Implémenter "sum", "some" et "every" avec "reduce".
Objets littéraux
let point = {
"x" : 12,
"y" : 24
};
- Peut servir d'espace-nom
- Les membres sont publics
- Accessible par envoi de message par index
Prototypes
function Point(x, y) { this.x = x; this.y = y; }
let p1 = new Point(12, 24);
this
référence toujours le contexte courant (sauf dans les fats arrows).
Méthodes
function Point(x, y) { this.x = x; this.y = y; this.f = function(){} }
Point.prototype.f = function() {};
Cela permet aussi le Monkeypatching
Transformation de contexte des méthodes/lambdas
lambda.call(obj, argA, argB...);
lambda.apply(obj, [argA, argB...]);
lambda.bind(obj)
Héritage classique
function Class(a, b, c) { Parent.call(this, a, b); this.c = c; }
Class.prototype = Object.create(Parent.prototype);
Les classes "à la Java"
- Nouvelle syntaxe plus expressive (selon certains)
- Des fonctions "un peu spéciale"
class Polygone {
constructor(hauteur, largeur) {
this.hauteur = hauteur;
this.largeur = largeur;
}
}
Multiples définitions
Les classes sont des "fonctions", donc des valeurs.let A = class {};
class A {}
Encapsulation
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return (this.formattedPrefix ? this.formattedPrefix: '') + this.firstName + ' ' + this.lastName;
}
set prefix(string) {
this.formattedPrefix = string + ' ';
}
}
var me = new Person('Flip', 'Stewart');
me.prefix = 'Super Dr.';
me.fullName
Héritage
class Animal {
constructor(nom) {
this.nom = nom;
}
parle() {
console.log(this.nom + ' fait du bruit.');
}
}
class Chien extends Animal {
parle() {
super.crie() // Référence la classe parente
console.log(this.nom + ' aboie.');
}
}
Modèles mélangeables
Les classes ne sont qu'un sucre syntaxique pour les prototypes
function Animal (nom) {
this.nom = nom;
}
Animal.prototype.crie = function () {
console.log(this.nom + ' fait du bruit.');
}
class Chien extends Animal {
crie() {
super.crie();
console.log(this.nom + ' aboie.');
}
}
Staticité de membres
- Préfix static comme en Java
- Retyper une classe
static get [Symbol.species]() { return Array; }
Héritage transversal
- Pas d'héritage multiple classique (trop de problèmes)
- Possibilité d'utiliser des mix-in's
Weird trick : Mixins
Les classes sont des valeurs.let mixinA = (base) => class extends base {...}
let mixinB = (base) => class extends base {...}
class B extends mixinB(mixinA(Parent)) {...}
Gestion des erreurs
throw new Error(message);
try ... catch
try ... finally
try ... catch ... finally
- Documentation de Error
instanceof
pour définir le typed'une exception dans un block catch.
Gestion des erreurs
try {
maRoutine(); // may throw three types of exceptions
} catch (e) {
if (e instanceof TypeError) {
// les instructions pour gérer TypeError
} else if (e instanceof RangeError) {
// les instructions pour gérer RangeError
} else if (e instanceof EvalError) {
// les instructions pour gérer EvalError
} else {
// les instructions pour gérer les autres exceptions
}
}
Exercice, interpréter Brainfuck
Un langage minimaliste (mais turing complet) !
Objectif
Implémenter un programme qui permet
d'exécuter du Brainfuck.
Implémenter un programme qui permet
d'exécuter du Brainfuck.
Liens utiles
Node.js: présentation
The official website defines Node as “a platform built on Chrome’s JavaScript runtime for easily building fast,
scalable network applications. Node.js uses an event-driven, non-blocking I/O model
that makes it lightweight and effi- cient, perfect for data-intensive real-time applications that run across
distributed devices.”
Historique
- Utiliser JavaScript en dehors du Navigateur
- Initié en 2009 par Ryan Dahl
- Sponsorisé par Joyent (voila pourquoi IO.js)
- Utilise l'interprêteur V8 de Google
- Est codé majoritairement en JavaScript
- Preuve que JavaScript est un langage complet
Node.js in a Nutshell
- Créé sur JavaScript
- Une platforme et non un framework
- Asynchrône et ordonnancé par des événements
- Désigné pour le traitement de données massif et les
applications temps réelles.
Modules
const mod = require('./mod.js');
const mod = require('../mod.js');
const mod = require('mod'); // node_modules
Exportation de fonctions
let f = function() { ... }
exports.f = f
require renvoie un objet qui contient tous lesL'utilisation des modules est possible "côté client" via "webpack".
éléments exportés dans un module.
NPM
npm search pkg
npm install pkg
npm install -g pkg
npm update
Créer un module
- Se rendre dans le dossier du projet
npm init
(crée un fichier package.json)- Utiliser le versionnement sémantique !
npm adduser
&&npm publish
Explication d'un fichier package
{
"name": "brainfuck-exec",
"version": "0.0.1",
"dependencies": {},
"description": "A small Brainfuck interpreter",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "babel src -d lib",
"exec": "node lib/index.js",
"solution": "node lib/solution.js"
},
"author": "xvw",
"license": "MIT",
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.18.2",
"babel-loader": "^6.2.8",
"babel-preset-es2015": "^6.18.0",
"readline-sync" : "^1.4.5"
}
}
Exercice
Créer un module et un paquet NPM pour les fonctions "some" et "every"
Un serveur web
- Génériquement
- A la PHP (via Apache/Nginx)
- A la Node.js
Notre première application Node.js !
// A simple hello server in Node JS
// Initialization
const http = require('http');
const server = http.createServer();
const port = 3030;
// Event handler
server.on('request', (request, result) => {
console.log('Incomming Query ! Youhou');
result.writeHead(200, {'Content-Type' : 'text/plain'});
result.end('Hello World\n');
});
// Server listening
server.listen(port);
console.log('Server running on localhost:'+port);
Programmation événementielle
- Un seul Thread
- Mais aucune opération bloquante !
- Utilisation de Callbacks
Ecouter des événements
objet.on(event, callback);
Emettre des événements
const Dispatcher = require('events').EventEmitter;
let obj = new Dispatcher();
obj.on('event', callback(*args));
obj.emit('event', *args);
Request et Result
server.on('request', (request, result) => {
- Objet définissant la réquête envoyée
- Stream sur lequel on écrit a renvoyer a l'utilisateur
Quelques modules utiles
let url = require('url');
let querystring = require('querystring');
let data = url.parse(request.url);
let path = data.pathname;
let query = querystring.parse(data.query)
Sur base de ces fonctions, on peut implémenter son système de routing !
DEMONSTRATION !
Programmer avec des fichiers
Un exemple simple
let fs = require('fs');
fs.readFile('./resource.json', function (er, data) {
console.log(data.toString);
})
Exercice (gros gros truc qui arrive là)
- Implémenter un serveur de fichiers statiques !
- Le fichier prendra en charge les fichiers .txt, .json et .html
- La partie exposée du serveur sera dans un fichier www
- Faites des petits modules et des petites fonctions
- Surtout... écrivez des tests unitaires pour vos fonctions !
Express : un framework minimaliste
- Framework très simple basé sur Node.js
- Proche de Sinatra
- Très facile à utiliser
- Couplable avec des middlewares et du templating
- Site officiel
Une première application
- Utilisation de Nodemon (à installer avec -g)
- Démonstration d'une application pas à pas
Effectuer des requêtes Http
Node.js est une technologie serveur... donc pas d'Ajax nécéssaire ! Exercice: Ecrivez un programme qui affiche proprement les données de:http://jsonplaceholder.typicode.com/posts
publierhttp://jsonplaceholder.typicode.com/posts/{ID}
récupérerhttps://jsonplaceholder.typicode.com/posts?userId={ID}
Récupérer
De la persistance avec Mysql
Le traitement d'une base de données est assez aisé car il existe beaucoupde bibliothèques.
N'hésitez pas à exécuter le fichier sql présent sur le dépôt (mysql-sample-1/sql).
Exercice final !
- Exposer la table jeux_video sous forme d'API REST.
- Rendre la liste de tous les jeux récupérable (GET /games)
- Accéder à un jeu (GET /game/id)
- Ajouter un jeu (POST /new/game)
- Créer un client console pour tester l'API
- Eviter les Callbacks Hell !