Programmation réticulaire
Transcription
Programmation réticulaire
Programmation réticulaire le langage Javascript Christian Queinnec Professeur émérite de l’UPMC Paracamplus by C.Queinnec Programmation réticulaire 1/71 I Cours dispensé à l’INSTA I en octobre 2015 by C.Queinnec Programmation réticulaire 2/71 Plan I Le langage Javascript I Prototypes I Mise en œuvre I Concurrence en Javascript I Techniques fonctionnelles by C.Queinnec Programmation réticulaire 3/71 Partie 1 Le langage Javascript by C.Queinnec Programmation réticulaire 4/71 Avertissement I Ce cours n’est pas un cours d’initiation à la programmation I Il passe en revue les éléments spécifiques, voire atypiques, de Javascript I Cette séquence ne s’intéresse qu’au langage indépendamment des mises en œuvre au sein des navigateurs. by C.Queinnec Programmation réticulaire 5/71 Historique I Créé par Brendan Eich en mai 1995 pour Netscape I puis re-nommé Javascript ! I quelques implantations divergentes: javascript, JScript, EcmaScript I et maintenant ES5, ES6 en cours et ES7 en préparation I implantations d’évaluateurs Javascript autonomes ou embarqués en navigateurs (Chrome, Explorer, Firefox, Opera) : Rhino, Node.js, V8, Nashorn, etc. by C.Queinnec Programmation réticulaire 6/71 Caractéristiques I langage typé dynamiquement I sûr(sic) mais assez permissif I procurant des prototypes (plutôt que des objets) I gestion mémoire automatique I pas nécessairement bien compilable I pas nécessairement efficace Il est utile de regarder les tests associés à ces transparents: Code pour Jasmine by C.Queinnec Programmation réticulaire 7/71 Syntaxe I Attention aux fins de lignes implicites! Écrivez plutôt v = 3 + 4; // et non v = 3 + 4; I commentaires à la C++ I identificateurs à la C et mots-clés réservés by C.Queinnec Programmation réticulaire 8/71 Données I nombres (représentés par des flottants 64bits) I donc entiers sur 54 bits I écritures hexadécimales (préfixe 0x) ou octales (préfixe 0) I isNan, isFinite I chaînes de caractères immuables mono-lignes encadrées par ’ ou " I échappement à la C avec \ I mais attention aux graphies \n ou \uXXXX I vrais booléens true et false mais toute valeur a une valeur de vérité by C.Queinnec Programmation réticulaire 9/71 Expressions rationnelles I aussi connues comme regexp I syntaxe dédiée à la Perl /^f(.*)?[^n-q]+$/ I Exemples: i f ( "foobar".search(/^fo+/) >= 0 ) { var r2 = new RegExp("f(o+)(.*)a"); r e t u r n r2.exec("foobar", "g"); // [ ’fooba’, ’oo’, ’b’, index: 0, input: ’foobar’ } by C.Queinnec Programmation réticulaire 10/71 Langage fonctionnel En Javascript, les fonctions sont des valeurs de première classe. functio n add (x, y) { r e t u r n x + y; } var plus = add; var suivant = f u n c t i o n (a) { r e t u r n plus(a, 1); } suivant("3"); // -> "31" by C.Queinnec Programmation réticulaire 11/71 Tables associatives I Syntaxe dédiée avec accolades I ou création via new Object() (rare!) I accès avec notation pointée (champ quelquefois non modifiable) I suppression de clé avec delete var point = { x: 11, y: 22 }; point.x == point.y / 2; point.x === point[’x’]; point.z = ’wtf’; ’z’ i n point; delete point.x; ! ( ’x’ i n point ); by C.Queinnec // pas de virgule finale Programmation réticulaire 12/71 Tableaux I Syntaxe dédiée avec crochets I ou création via new Array(taille) I accès avec index (débutant à 0) I Tables associatives à clé numérique positive ou nulle. I Méthodes prédéfinies pour tableaux, piles, files var a = [ ’a’, ’b’, [5+6, ’b’] ]; // pas de virgule fi a[1] == a[2][1]; a.length == 3; a[44] = ’d’; a.length == 45; a[’c’] = 33; a[’c’] == a.c; a[’1’] == a[1]; // [ ’a’, ’b’, [ 11, ’b’ ], , , , , , ’d’, c: 33 ] by C.Queinnec Programmation réticulaire 13/71 Valeurs spéciales I null I undefined n’est pas un mot-clé var truc; truc === undefined; truc !== n u l l ; truc = []; truc[9] === undefined; truc.neuf === undefined; by C.Queinnec Programmation réticulaire 14/71 Classes prédéfinies var msg = "Coucou"; typeof(msg) === ’string’; ! ( msg instanceof String); msg.length === 6; var cmsg = new String(msg); typeof(cmsg) === ’object’; cmsg instanceof String; cmsg.length === 6; msg !== cmsg; msg == cmsg; Distinguer valeur immédiate et instance d’une classe. Même chose pour Number et Boolean by C.Queinnec Programmation réticulaire 15/71 Conversions I Javascript est assez laxiste I Notions étranges de Vrai/Faux I Conversion nombre vers chaîne et inversement [4] * [4] // [] * [] // [] * {} // [4, 4] * [4, 4] // {} * {} // 16 0 NaN NaN NaN Mais aussi (sic): new Boolean(false) == false new Boolean(false)?true:false == true by C.Queinnec Programmation réticulaire 16/71 Instructions I Comme en C pour if, else, while, do, break, continue, for, switch, case, break, default, return I Comme en Java pour try, catch, throw, finally I Et, en Javascript, énumération des clés propres d’un objet (cf. Object.hasOwnProperty()) et notion de clé énumérable. f o r ( var key i n object ) { var value = object[key]; } by C.Queinnec Programmation réticulaire 17/71 Portée I I portée globale portée fonction var g0; // g0 a une portée globale g1 = 3; // g1 a une portée globale (non use strict) functio n f1 (x) { g2 = x; // g2 a une portée globale var l4 = 1; // l4 visibles en f1 i f ( false ) { var l5 = l3; // l5, l3 visible dans f1 } f o r ( var l3 i n g0 ) { // l6 visible dans f1 } var f2 = f u n c t i o n (y) { // y visible en f2 var ll7 = l6; // ll7 visible en f2 } } ES6 introduit la véritable portée lexicale avec let by C.Queinnec Programmation réticulaire 18/71 Environnement global I Il existe un objet global I Dans un navigateur, il se nomme window I En Node.js, c’est global I Dans un module Node.js, c’est module gg = 44; global.gg === global[’gg’]; var ggg; global.ggg === global[’ggg’]; ggg = 55; global.ggg === global[’ggg’]; by C.Queinnec Programmation réticulaire 19/71 Comparaisons I Distinguer l’égalité == I et l’identité === I Toujours préférer l’identité. NaN !== NaN NaN != NaN 3 !== 1/0 3 != 1/0 undefined === undefined n u l l !== undefined n u l l == undefined [1] != [1] {a: 1} != {a: 1} "chaine" == "cha" + "ine" "chaine" === "cha" + "ine" 11 == ’11’ by C.Queinnec 11 > 3 "11" < "3" "11" > 3 1 < 1 + 1e-15 1 >= 1 + 1e-16 [] == false Programmation réticulaire 20/71 Opérateurs I Comme en C I + concatène des chaînes si l’un au moins de ses arguments est une chaîne I Nouveaux mots-clé in, instanceof, typeof, new, delete i f ( "key" i n object ) ... f o r ( var key i n object ) ... i f ( s instanceof String || typeof(s) == ’string’ ) ... by C.Queinnec Programmation réticulaire 21/71 Fonctions functio n bar (x) { ... } var foo = f u n c t i on (x) { r e t u r n x === arguments[0]; } var hux = f u n c t i on () { r e t u r n arguments.length; } var fns = [ bar, foo, hux ]; fns[1](fns[0]); hux(11, 22, 33); hux.call( n u l l , 11, 22, 33); hux.apply( n u l l , [11, 22, 33]); // À suivre // À suivre Attention, si ES6 impose que les récursions terminales soient correctement implantées, peu d’évaluateurs le proposent. by C.Queinnec Programmation réticulaire 22/71 Partie 2 Prototypes by C.Queinnec Programmation réticulaire 23/71 Objets I Javascript n’est pas un langage à objets mais un langage à prototypes. I Les “méthodes” sont des champs dont les valeurs sont des fonctions. var o = { a: 2, m1: f u n c t i o n (b) { r e t u r n t h i s .a + b; } }; o.m1(5); o.m2 = f u n c t i o n (c) { r e t u r n t h i s .a * c; }; o.m2(5); by C.Queinnec Programmation réticulaire 24/71 Constructeurs functio n Person (firstname, lastname) { // constructeur t h i s .firstname = firstname; // en fait initialiseur t h i s .lastname = lastname; t h i s .old = 0; t h i s .setOld = fu n c t i o n (old) { t h i s .old = old} } var p1 = new Person("Jean", "Dupont"); p1.lastname == p1[’lastname’]; p1.setOld(42); p1.old == 42; functio n fullname (msg) { r e t u r n msg + t h i s .firstname + ’ ’ + t h i s .lastname; } fullname.call(p1, ’Hello ’); p1.fullname = fullname; p1.fullname(’Hello ’); by C.Queinnec Programmation réticulaire 25/71 Blocs d’activation les blocs d’activation (ou frames) correspondent à la pile de contrôle. var g = 100; var f = f u n c t i o n (x) { var y = 33; var g = f u n c t i o n (y) { r e t u r n x * y; // x libre dans g } r e t u r n [ g(x+y), g]; } f(g+1)[1](44); by C.Queinnec Programmation réticulaire 26/71 Blocs d’activation Avant appel à f: this=window window: g: 100 f: f env by C.Queinnec Programmation réticulaire 27/71 Blocs d’activation Pendant l’appel à f(g+1): this window window: parent arguments: g: 100 f: f env x: 101 y: 33 g: by C.Queinnec callee: [0]: 101 g env Programmation réticulaire 28/71 Blocs d’activation Pendant l’appel à f(g+1)[1](44): window parent window: arguments: g: 100 f: f env x: 101 y: g: 33 callee: [0]: 101 g env this parent arguments: y: by C.Queinnec 44 callee: [0]: 44 Programmation réticulaire 29/71 Environnements Toute fonction est une fermeture (closure). Lorsque l’on souhaite accéder à une variable, on la cherche dans l’environnement puis dans l’environnement de définition de la fonction. var mkcounter = f u n c t i o n (start) { var count = start; var counter = fu n c t i o n (increment) { r e t u r n (count += (increment || 1)); } r e t u r n counter; } var counter1 = mkcounter(10); var counter2 = mkcounter(100); counter1(); counter2(1); counter1(); by C.Queinnec Programmation réticulaire 30/71 Environnements Avant l’appel à mkcounter(10): this=window window: mkcounter: env by C.Queinnec Programmation réticulaire 31/71 Environnements Pendant l’appel à mkcounter(10): this=window parent window: mkcounter: env arguments: callee: start: 10 [0]: count: 10 counter: by C.Queinnec 10 env Programmation réticulaire 32/71 Environnements Après var counter1 = mkcounter(10): this=window parent window: mkcounter: arguments: callee: counter1: start: 10 [0]: count: 10 env counter: by C.Queinnec 10 env Programmation réticulaire 33/71 Environnements Pendant l’appel à counter2(1) (après counter1()): this=window parent window: mkcounter: arguments: callee: counter1: start: 10 [0]: count: 11 env counter2: counter: 10 env parent parent arguments: callee: increment:1 [0]: arguments: callee: start: 100 [0]: 100 10 count: 100 by C.Queinnec 1 counter: env Programmation réticulaire 34/71 Fermetures Les fermetures capturent des liaisons pas des valeurs! var foo = ( f u n c t i o n (shared) { r e t u r n { get: f u n c t i o n () { r e t u r n shared; }, set: f u n c t i o n (v) { shared = v; } }; })(10); foo.get() == 10; foo.set(22); foo.get() == 22; by C.Queinnec Programmation réticulaire 35/71 Captures d’index var fnsA = []; f o r ( var i=0 ; i<5 ; i++ ) { fnsA.push( f u n c t i o n () { r e t u r n i }); } fnsA[0]() == fnsA[1](); fnsA[2]() == 5; var fnsB = []; f o r ( var i=0 ; i<5 ; i++ ) { ( fun c t i o n (ii) { fnsB.push( f u n c t i o n () { r e t u r n ii }); })(i); } expect(fnsB[2]()).toBe(2); expect(fnsB[3]()).toBe(3); by C.Queinnec Programmation réticulaire 36/71 Modules de node.js ( functi o n (require, exports, module) { // {{{ Contenu de module.js: // module est l’objet global courant // lister les dependances: var autre = require(’...’); // exporter module.exports.f = f u n c t i o n () { ... }; // }}} fin de module.js })(); // Dans un autre module: var m = require(’module.js’); // ie module.exports // utiliser m.f() by C.Queinnec Programmation réticulaire 37/71 Méthode d’instance Comment partager des méthodes ? functio n Truc (chose) { t h i s .chose = chose; // méthode d’instance: t h i s .setChose = f u n c t i o n (chose) { t h i s .chose = chose; } } var t1 = new Truc(1); var t2 = new Truc(2); t1.setChose != t2.setChose; t1.machin = f u n c t i o n () { r e t u r n ’binz’ }; t1.machin(); t2.machin(); // TypeError: undefined is not a function by C.Queinnec Programmation réticulaire 38/71 Prototypes I Tout objet est lié à son constructeur I Toute fonction (donc tout constructeur) est associé à un prototype. functio n Truc (chose) { t h i s .myKind = ’truc’; t h i s .chose = chose; } var t1 = new Truc(1); var t2 = new Truc(2); t1.constructor == Truc; t1.machin = 111; Truc.prototype.binz = f u n c t i o n (d) { r e t u r n ( t h i s .chose += d); } t1.binz(10); t2.binz(10); by C.Queinnec Programmation réticulaire 39/71 Prototypes I En fait, tout objet a un prototype accessible par Object.getPrototypeOf() I Dans o.f, on cherche d’abord f dans o puis dans le prototype de o puis dans le prototype du prototype de o, etc. window: Truc: Truc t1: prototype: t2: prototype prototype constructor: constructor: chose: chose: prototype 2 myKind: truc 1 constructor: binz: myKind: truc machin: 111 by C.Queinnec Programmation réticulaire 40/71 this I À tout moment, il y a un this I Au début, this est l’objet global functio n incr (dx) { t h i s .x += dx; t h i s .incr = incr; return t h i s } var c = {x: 10}; incr.call(c, 2).incr(3); c.x == 15; by C.Queinnec // cascade Programmation réticulaire 41/71 Capture de this this est un mot-clé pas une variable donc non capturable dans une fermeture. functio n Foo () { t h i s .count = 0; t h i s .mkincr = fu n c t i o n (d) { r e t u r n f u n c t i o n () { r e t u r n ( t h i s .count += d); } } } var vf = new Foo(); var f = vf.mkincr(2); f(); vf.count == 0; f.call(vf); vf.count == 2; by C.Queinnec f u n c t i o n Foo () { var self = t h i s ; t h i s .count = 0; t h i s .mkincr = f u n c t i o r e t u r n f u n c t i o n () r e t u r n (self.cou } } } var vf = new Foo(); var f = vf.mkincr(2); f(); vf.count == 2; Programmation réticulaire 42/71 Création d’instance new Chose(’a’, 2); new Chose(’a’, 2) this prototype constructor: x: ’a’ y: 2 by C.Queinnec Chose prototype Programmation réticulaire 43/71 Héritage I Chainer les prototypes. var p = Object.create(o); // clonage Object.getPrototypeOf(p) === o; Object.getPrototypeOf(Object) === n u l l ; // existe aussi Object.setPrototypeOf(obj, proto) by C.Queinnec Programmation réticulaire 44/71 Héritage de classes functio n Worker (name) { t h i s .name = name; }; var getSalary = fu n c t i o n () { r e t u r n 1 }; Worker.prototype.getSalary = getSalary; functio n Plumber (nickname) { Worker.call( t h i s , nickname); // super() t h i s .nickname = nickname; }; Plumber.prototype = Object.create(Worker.prototype); Plumber.prototype.constructor = Plumber; Plumber.prototype.getSalary = f u n c t i o n () { r e t u r n 10 * Worker.prototype.getSalary(); // super.get }; by C.Queinnec Programmation réticulaire 45/71 Héritage de classes var util = require(’util’); util.inherits(Plumber, Worker); Plumber prototype: // En Node.js Worker prototype: jean prototype constructor: sayWelcome: prototype constructor: fixPipe: by C.Queinnec prototype constructor: getSalary: Programmation réticulaire 46/71 Héritage de classes - remarques I (1) permet à un Plumber d’avoir les méthodes d’un Worker mais new Plumber().contructor === Worker I ce que corrige (2). functio n Worker (name) { t h i s .name = name; }; functio n Plumber (nickname) { Worker.call( t h i s , nickname); // super() t h i s .nickname = nickname; }; Plumber.prototype = Object.create(Worker.prototype); // Plumber.prototype.constructor = Plumber; // (2) by C.Queinnec Programmation réticulaire 47/71 Variable et champ (ou méthode) I Les variables sont recherchés dans l’environnement puis dans le parent de l’environnement puis etc. I Lorsqu’une variable est modifiée, elle est modifiée dans son environnement de définition. I Les champs sont cherchés dans l’objet puis dans le prototype de l’objet puis dans le prototype du prototype de l’objet puis etc. I Lorsqu’un champ est modifié, la modification est effectuée dans this. Javascript reference by C.Queinnec Programmation réticulaire 48/71 Un peu d’ordre I Javascript est assez complexe I à partir d’ES5, ajout de ’use strict’ en tête de fonction ou de module I Plus de delete sur des variables I Plus de références sur des variables globales non déclarées I etc. Cf. notes sur "use strict" by C.Queinnec Programmation réticulaire 49/71 Partie 3 Mise en œuvre by C.Queinnec Programmation réticulaire 50/71 Mise en œuvre Pour ce cours: I L’IDE à utiliser: Atom I L’évaluateur Javascript: Node.js I Le gestionnaire de module: npm I Les tests sont écrits en Jasmine (cf. spec/tests-spec.js) I Le code est vérifié avec jshint L’installation de node.js installe aussi le gestionnaire de modules npm. L’option -g installe pour toute la machine plutôt que pour le seul projet. cd /usr/local # nodejs.org tar --strip-components 1 -xzf node-v0.12.7-linux-x npm install -g jshint npm install -g jasmine dpkg -i atom-amd64.deb # atom.io by C.Queinnec Programmation réticulaire 51/71 Node I Évaluation d’un fichier avec node I Documentation I Interagir avec l’OS: l’objet process I Créer un serveur HTTP node file.js node debug file.js by C.Queinnec Programmation réticulaire 52/71 Vérification I un linter: jshint I paramétré par .jshintrc I intégré dans Atom by C.Queinnec Programmation réticulaire 53/71 Test I TDD (Test Driven Development avec Jasmine ou Mocha I ou plutôt BDD (Behavior Driven Development) I avec les usuels beforeAll, beforeEach, afterEach, afterAll I Jasmine supporte les rappels asynchrones I Cf. quelques tests pour ce cours by C.Queinnec Programmation réticulaire 54/71 Tests // Jasmine: describe("my application", function () { it("should perform concatenations", function () { expect(3 + "5").toBe(’35’); }); }); // Mocha: describe("my application", function () { it("performs concatenations", function () { assert.equal(3 + "5", ’35’); //(3 + "5").should.equal(’35’); }); }); by C.Queinnec Programmation réticulaire 55/71 Partie 4 Concurrence en Javascript by C.Queinnec Programmation réticulaire 56/71 Concurrence I Javascript est mono-tâche: à tout moment, au plus un code utilisateur est en cours d’exécution. I C’est un modèle non-préemptif: un calcul infini, une attente active de l’utilisateur bloquent donc tout. I La bibliothèque d’exécution est multi-tâches et signale, par le biais de rappels (ou renvois) (ou callback), la survenue de certains événements. I Node procure des bibliothèques avec rappels pour tous les cas où il peut y avoir une attente. by C.Queinnec Programmation réticulaire 57/71 Messages I La bibliothèque d’exécution de Javascript maintient un ensemble de tâches en attente (A) et un ensemble de tâches pouvant être poursuivies (P). I Si une tâche de A n’a plus besoin d’attendre, elle est transférée en P. I Lorsque Javascript a fini de traiter une tâche de P et si P n’est pas vide, il prend et exécute une nouvelle tâche de P. I En particulier, l’ordre de traitement des rappels ne peut être prédit. by C.Queinnec Programmation réticulaire 58/71 Rappels var timeout1 = setTimeout( f u n c t i o n () { console.log(’rappel timeout1’); }, 123456); var timeout2 = setTimeout( f u n c t i o n () { console.log(’rappel timeout2’); }, 0); var interval = setInterval( f u n c t i o n () { console.log(’rappel interval’); }, 987); console.log(’on y va’); f o r ( var i=0 ; ; i++ ) { i = 0; // boucle infinie } by C.Queinnec Programmation réticulaire 59/71 Rappels et serveurs var http = require(’http’); functio n handle (request, response) { // npm install httpdispatcher response.end( ’URL=’ + request.url, fu n c t i o n () { console.log(’response sent’); }); } var server = http.createServer(handle); server.listen(61234, f u n c t i o n () { console.log("Server listening"); }); console.log(’end of file’); by C.Queinnec Programmation réticulaire 60/71 Rappels et clients var util = require(’util’); http.get(’http://www.insta.fr/’, f u n c t i o n (response) { response.on(’data’, f u n c t i o n (data) { console.log(’response is ’ + data); }); console.log(’got response’); }).on(’error’, f u n c t i o n (e) { console.log("Got error: " + e.message); }); by C.Queinnec Programmation réticulaire 61/71 Partie 5 Techniques fonctionnelles by C.Queinnec Programmation réticulaire 62/71 Fonctionnelle var map = f u n c t i on (array, fn) { var result = []; f o r (var i=0 ; i<array.length ; i++ ) { result[i] = fn(array[i]); } r e t u r n result; } map([1, 2, 3], f u n c t i o n (x) { r e t u r n x * x; }); by C.Queinnec Programmation réticulaire 63/71 Fonctionnelle var toggle = f u n c t i o n (f1, f2) { var counter = 0; r e t u r n f u n c t i o n () { i f ( 0 === (counter++ % 2) ) { r e t u r n f1.apply(toggle, arguments); } else { r e t u r n f2.apply(toggle, arguments); }; }; }; var t = toggle( f u n c t i o n (a) { r e t u r n 2 * a; }, f u n c t i o n (b) { r e t u r n 5 * b; }); t(1); // 2 t(2); // 10 t(3); // 6 by C.Queinnec Programmation réticulaire 64/71 Memoization var memo = f u n c t i o n (fn) { var result; r e t u r n f u n c t i o n () { i f ( ! result ) { result = fn.apply( t h i s , arguments); } r e t u r n result; }; }; var f = memo( f u n c t i o n () { var limit = 1000*100 f o r ( var i=0 ; i<limit+1 ; i++ ) { f o r ( var j=0 ; j<limit+1 ; j++ ) { i f ( i==limit && j==limit ) { r e t u r n 42; }}} }); f(); f(); by C.Queinnec Programmation réticulaire 65/71 Bibliothèques fonctionnelles Encore plus de techniques fonctionnelles dans: bibliothèque Underscore ou son successeur lodash var __ = require(’lodash); var f = __.memoize( f u n c t i o n () { var limit = 1000*100 f o r ( var i=0 ; i<limit+1 ; i++ ) { f o r ( var j=0 ; j<limit+1 ; j++ ) { i f ( i==limit && j==limit ) { r e t u r n 42; }}} }); f(); f(); by C.Queinnec Programmation réticulaire 66/71 Trampoline Calculer en bas de pile plutôt qu’en haut! f u nc tio n cpsfact (n, cb) { f u n c t io n cpsfactaccum (n, r) { i f ( n === 1 ) { r e t u r n cb(r); } else { r e t u r n cpsfactaccum(n - 1, r * n); } } r e t u r n cpsfactaccum(n, 1); } var k = f u nc t i o n (fact100) { ... }; var fact100 = cpsfact(100, k); by C.Queinnec Programmation réticulaire 67/71 Trampoline (suite) f u nc tio n cpsfact (n, cb) { f u n c t io n cpsfactaccum (n, r) { i f ( n === 1 ) { r e t u r n f u n c t io n () { r e t u r n cb(r); }; // <} else { r e t u r n cpsfactaccum(n - 1, r * n); } } r e t u r n cpsfactaccum(n, 1); } var k = f un c t i o n (fact100) { ... }; var fact100 = (cpsfact(100, k))(); // <- by C.Queinnec Programmation réticulaire 68/71 Continuation(callback) Passing Style var euclide = f un c tio n (n, d, cb) { var q = Math.floor(n / d); r e t u r n cb(q, n - q*d); }; // Si pgcd(n, p) = 1 alors il existe u et v // tels que 1 = u*n + v*p var bezout = f unc ti o n (n, p, cb) { r e t u r n euclide(n, p, fu nc tio n (q, r) { i f ( r === 0 ) { i f ( p === 1 ) { r e t u r n cb(0, 1); } else { throw new Error("gcd != 1"); } } else { r e t u r n bezout(p, r, f un c ti o n (u, v) { r e t u r n cb(v, u - v*q); }); } }); }; bezout(53, 17, f u n cti on (u, v) { r e t u r n [u, v]; }); by C.Queinnec Programmation réticulaire 69/71 Promesses var Peuclide = func tio n (n, d) { r e t u r n new Promise( fu n ction (resolve, reject) { i f ( d !== 0 ) { var q = Math.floor(n / d); resolve([q, n - q*d]); } else { reject(new Error("diviseur nul")); } }); }; var pe = Peuclide(53, 17); pe.then( fun ct i on (value) { console.log(1, value); }, fu n ct ion (error) { console.log(error.toString()); }); pe.then( fu nc t i on (value) { console.log(2, value); }); by C.Queinnec Programmation réticulaire 70/71 Cascades de promesses Cf. Spécification, économise des try catch var pe = Peuclide(53, 17); pe.then( f u nc t i o n (value1) { i f (...) { r e t u r n value2; } else { throw new Error(...); } }) .then( f u nc t i o n (value2) { ... }) .catch( f u n ct i o n (error) { r e t u r n value3; }) .then( f u n c t io n (value3) { ... }); by C.Queinnec Programmation réticulaire 71/71