Slide 1

Slide 1 text

javascript Promises

Slide 2

Slide 2 text

Sylvain ZYSSMAN @sylzys

Slide 3

Slide 3 text

vous avez dit « asynchrone » ?

Slide 4

Slide 4 text

synchrone Javascript (y compris V8) est mono-thread. ! function getUser(name) { var sql = 'SELECT * FROM users WHERE name=?'; var user = query(sql, name); //<-- bloquant if (! user) throw new Error ('no user!' ); return user; }

Slide 5

Slide 5 text

asynchrone function getUser (name, callback) { var sql = 'SELECT * FROM users WHERE name=?'; query(sql, name, function (error, user ) { if (error) { callback(error); } else if (!user) { callback(new Error ('no user!' )); } else { callback(null , user); } }); }

Slide 6

Slide 6 text

Les callbacks C’est quoi ?

Slide 7

Slide 7 text

callbacks Fonction passée en paramètre à une autre fonction, et exécutée au sein de celle-ci. ! var talk = document.getElementById("talk"); talk.addEventListener("click", function(event){ alert("You chose a talk"); }); ! $('#talk').click(function(event) { alert("You chose a talk"); });

Slide 8

Slide 8 text

callbackS fs.readFile('/etc/passwd', function (err, data) { if (err) throw err; console.log(data); }); function mainCode(callback){ doSomething(); callback(); } ! function myCallback(){ console.log("This is my callback"); } ! mainCode(myCallback);

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

callback hell getEvent("CaenJS", function (error, _event){ if (error) { manageError(error); } else { getTalks(_event, function(error, talks){ if (error) { manageError(error); } else { getSpeakerDetails(talks[0].id, function(error, details){ if (error) { manageError(error); } else { displayInUI(details); } }); } }); } });

Slide 11

Slide 11 text

callback hell fs.readdir(source, function(err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function(filename, fileIndex) { console.log(filename) gm(source + filename).size(function(err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function(width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(destination + 'w' + width + '_' + filename, function(err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } }) http://callbackhell.com/

Slide 12

Slide 12 text

callbackS Return / Throw function getUser (name, callback) { var sql = 'SELECT * FROM users WHERE name=?'; query(sql, name, function (error, user ) { //personne ne récupère cette valeur return user; }); } function getUser (name, callback) { var sql = 'SELECT * FROM users WHERE name=?'; query(sql, name, function (error, user ) { //personne ne catch l'exception if(error) throw error; }); }

Slide 13

Slide 13 text

callbackS • Lisibilité (nesting) • Complexité du code • Maintenabilité • Pas de garantie d’exécution • Return ? Throw ? • Simplicité • Poids réduit

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Les promises C’est quoi ?

Slide 16

Slide 16 text

promises • Prémices aux alentours de 1989 • Principe actuel inspiré du langage E (Mark Miller) • Principe bcp utilisé en dehors du JS • 1re version des specs par le groupe CommonJS • Spéc actuelle Promises/A+ • Ember, Angular, Dojo, etc.

Slide 17

Slide 17 text

promises Représente le résultat d’une opération asynchrone. Objet 1re classe, qui aura, à un moment, une valeur. 3 états possibles : • Pending • Fulfilled (renvoie une valeur) • Rejected (renvoie une raison) ! Permet de retrouver les bénéfices du synchrone : return, throw, catch, re-throw

Slide 18

Slide 18 text

Les promises Pourquoi ?

Slide 19

Slide 19 text

promises • Rendre disponibles en « asynchrone » les opérations existantes en « synchrone » : • return / throw / catch / rethrow ! • Bénéficier d’un callstack en mode asynchrone Pourquoi

Slide 20

Slide 20 text

promises • Requête(s) AJAX (simple, chainées..) • Chargement asynchrone d’asset avec actions à réaliser • Animation • … Cas d’utilisation

Slide 21

Slide 21 text

Les promises Comment ?

Slide 22

Slide 22 text

promises Garanties promiseForResult.then(onFulfilled, onRejected); ! onFulfilled OU onRejected sera appelée, une seule fois. ! onFulfilled sera appelée avec une valeur (return) onRejected sera appelée avec une raison du rejet (thrown exception)

Slide 23

Slide 23 text

promises Chaînage var transformedPromise = originalPromise.then(onFulfilled, onRejected); ! Si le handler appelé renvoie : ! • une valeur : transformedPromise passera à l’état « resolved » avec cette valeur ! • une promise : transformedPromise adopte son état ! Si le handler appelé renvoie une exception, transformedPromise passera en « rejected » avec l’exception renvoyée. !

Slide 24

Slide 24 text

promises Return / Throw getUser('sylv') .then(function(user) { if(!user){ throw new Error('no user!'); } return user.name; });

Slide 25

Slide 25 text

promises Création var promise = new Promise(function(resolve, reject) { // do something ! if (/* everything is OK */) { resolve("Good !"); } else { reject(Error("UhOh...")); } }); promise.then(function(result) { console.log(result); // "Good !" }, function(err) { console.log(err); // Error: "UhOh..."" });

Slide 26

Slide 26 text

promises step1(function (value1) { step2(value1, function(value2) { step3(value2, function(value3) { step4(value3, function(value4) { // Do something with value4 }); }); ! }); }); ! ! Q.fcall(promisedStep1) .then(promisedStep2) .then(promisedStep3) .then(promisedStep4) .then(function (value4) { // Do something with value4 }).done(); Callback Hell ?

Slide 27

Slide 27 text

promises Exceptions ! try { var v1 = step1('foo'); var v2 = step2(v1); var v3 = step3(v2); var v4 = step4(v3); } catch (error) { handleError(error); } Synchrone Callbacks var handleError = console.log; ! step1('foo', function (error, v1) { if (error){ handleError(error); } else { step2(v1, function (error, v2){ if (error){ handleError(error); } //[…] else { //do something with v4 } }); } }); } }); } });

Slide 28

Slide 28 text

promises Exceptions promisedStep1('foo') .then(promisedStep2) .then(promisedStep3) .then(promisedStep4) .then(function (value4) { // Do something with value4 }) .then(undefined, handleError); Promises ! try { var v1 = step1('foo'); var v2 = step2(v1); var v3 = step3(v2); var v4 = step4(v3); } catch (error) { handleError(error); } Synchrone

Slide 29

Slide 29 text

promises • (Encore) peu d’implémentation natives • Certaines librairies non conformes aux specs • CallStack • Garanties • Return / Throw • Catch / Rethrow

Slide 30

Slide 30 text

Les promises Librairies

Slide 31

Slide 31 text

librairies Environ 30 librairies conformes à Promises/A+ ! Normées, donc peuvent s’échanger des promises entre elles

Slide 32

Slide 32 text

Librairies https://github.com/kriskowal/q ! Permet également d’utiliser des Promises en remote var Q = require("q"); var Connection = require("q-comm"); var remote = Connection(port, local); // a promise for a remote object! var userPromise = remote.getUser(); twitter.com/domenic Q.js

Slide 33

Slide 33 text

Librairies https://github.com/petkaantonov/bluebird ! bind(), call(), cancel(), join(), timers… BlueBird

Slide 34

Slide 34 text

Librairies https://github.com/tildeio/rsvp.js/ RSVP.js When.js https://github.com/cujojs/when http://msdn.microsoft.com/en-us/library/windows/apps/ br211867.aspx WinJS

Slide 35

Slide 35 text

Et maintenant • Les Promises sont intégrées à ES6 • Les API DOM les utiliseront aussi • Large utilisation dans Angular (templates, etc.) • Utilisation dans Ember, Dojo…

Slide 36

Slide 36 text

vanilla Certaines APIs DOM ayant des succès/échecs asynchrones utilisent les Promises (gestion de quota, événements de chargement de pontes, ServiceWorker, .… ! Implémentation native partielle dans certains navigateurs. ! Chrome : promesses activées par défaut dans Canary. Firefox : la dernière nightly, intègre les promesses. ! Pas encore d’implémentation complète ou conforme à 100% !

Slide 37

Slide 37 text

BONUS La plupart des librairies offre des fonctions / patterns utiles ui.startSpinner(); getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend) .catch(ui.error) .finally(ui.stopSpinner) .done(); twitter.com/domenic All, spread, map, invoke, denodeify …

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

toolbox • https://www.youtube.com/watch?v=hf1T_AONQJU • http://promisesaplus.com/implementations • http://www.html5rocks.com/fr/tutorials/es6/promises/ • http://domenic.me/2012/10/14/youre-missing-the-point- of-promises/ • http://fr.slideshare.net/domenicdenicola/promises- promises • http://fr.slideshare.net/domenicdenicola/callbacks- promises-and-coroutines-oh-my-the-evolution-of- asynchronicity-in-javascript • http://blog.carbonfive.com/2013/10/27/the-javascript- event-loop-explained/

Slide 40

Slide 40 text

MERCI !

Slide 41

Slide 41 text

CREDITS • Images : • Balakov - https://www.flickr.com/photos/balakov • Fonts : • Roboto - By Dharma Type // Dharma Type Font License v1.00 • Bebas Neue - By Christian Robertson // Apache License v2.00