logo

Formation NodeJS

Formation NodeJS

Xavier Van de Woestyne - Novembre 2016
logo

Bonjour !

  • 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
Jour 2 : NodeJS et son éco-système
  • 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
Jour 2 : Programmation server-side
  • 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
Jour 3 : Programmation parallèle avancée
  • 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").
Dans le monde JavaScript, l'interprêteur est dans le navigateur.

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
Liens utiles

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`
La portée lexicale est partiellement
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)
Les fonctions sont des valeurs du langage !

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

    On utilise instanceof pour définir le type
    d'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.
    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 les
    éléments exportés dans un module.
    L'utilisation des modules est possible "côté client" via "webpack".

    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);
  • Evènements du module http
  • Exercice: Ajouter un message quand un client se connecte au serveur
  • 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 publier
    • http://jsonplaceholder.typicode.com/posts/{ID} récupérer
    • https://jsonplaceholder.typicode.com/posts?userId={ID} Récupérer

    Solution au callbackHell

    De la persistance avec Mysql

    Le traitement d'une base de données est assez aisé car il existe beaucoup
    de 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 !

    Pour aller plus loin