SlideShare a Scribd company logo
1 of 75
Les Promises
Javascript
Javascript et son
Event Loop
Commençons par analyser en détail comment
Javascript gère un problème vieux comme le
développement : Le fonctionnement asynchrone.
Event Loop
• Javascript est essentiellement un langage
asynchrone (en opposition à « procédural »)
• On utilise souvent cette structure évènementielle en
définissant des « écouteurs » d’évènements (Par
exemple avec l’event object model  )
Event Loop
Event Loop
L’ avantage du modèle est de ne pas bloquer le
processus principal (comme par exemple le
navigateur ou votre programme Node.js) pendant
l’attente de l’évènement.
Event Loop
En développement, on appelle une opération
synchrone lorsqu’elle est exécutée « telle que l’on
peut la lire » (barbarisme, mais bon).
Prenons l’exemple en PHP de la récupération du
contenu (HTML) d’une url :
Event Loop
Event Loop
Ce script va être exécuté ligne par ligne et afficher
le résultat suivant :
On lance
Etape 2 0.25
Le temps écoulé pendant le téléchargement de l’url
(0,25 seconde) correspond également au temps
pendant lequel le programme est bloqué.
Si le téléchargement prend plusieurs secondes
(voir plus), c’est donc problématique.
Event Loop
Dans le cadre d’une application avec une interface
graphique (par exemple), on ne pas peut se le
permettre !
On a donc créé les threads.
Event Loop
Sans rentrer dans les
détails, il s’agit de créer
une unité d’exécution
parallèle à notre
programme qui aurait ici le
noble rôle d’attendre un
évènement ou d’effectuer
une tâche sans bloquer
notre interface.
Event Loop
Contrairement à beaucoup d’autres langages
Javascript n’a pas de mécanismes de gestion des
threads, et pour cause, il n’est exécuté que dans
un seul(*)
thread.
(*) : Ce n’est pas tout à fait vrai, mais peu importe ici…
Event Loop
En Javascript, on règle le problème avec une toute
autre méthode :
L’Event Loop !
Event Loop
L’Event Loop (la boucle d’évènements, donc) est
appelée ainsi puisqu’on peut la conceptualiser
avec le pseudo code suivant :
TANT_QUE boucle.attend_message()
boucle.prochain_message()
FIN_TANT_QUE
• L’Event Loop est donc une pile de messages où
chaque message est une fonction à exécuter.
• Les messages sont donc empilés à chaque fois
qu’un évènement auquel on a attaché un ou
plusieurs callbacks (écouteurs) survient.
• Et ils sont donc dépilés (au fur et à mesure) par
la boucle d’évènement.
Event Loop
Event Loop
Petit interlude « Loi Toubon » avant
d’en arriver à parler de butineurs.
• callback: Ecouteur (fonction a exécuter sur un
évènement)
• message: Fonction empilée lors d’un
évènement (callback en attente donc!)
• event loop: La boucle d’évènement permanente
qui dépile les message.
Voilà, ça c’est fait.
Event Loop
Donc lorsque l’on ajoute le callback suivant :
On précise « A chaque fois que l’évènement
« resize » intervient sur l’objet window, empile le
message replace_elements dans l’event loop.
Event Loop
Deux points importants !
Event Loop
Nous avons bien précisé
replace_elements
et non pas
replace_elements()
La deuxième notation reviendrait à dire exécute
immédiatement la fonction replace_elements puis
place sa valeur de retour comme callback de
l’évènement.
(Ceci représente 10^42 questions sur StackOverflow…)
Event Loop(Ceci représente aussi 10^42 questions sur StackOverflow…)
Affichera :
1 … 3 … 2 … 4 !
Ne jamais confondre sens de lecture du code et
logique d’event loop :
Event Loop
Enfin, si l’on reprend notre pseudo code :
TANT_QUE boucle.attend_message()
boucle.prochain_message()
FIN_TANT_QUE
On remarque que les messages sont exécutés un
par un ; il est donc d’usage de faire des callbacks
rapides, sous peine de voir nos prochains
évènements traités longtemps après être survenu.
Et puis ça aussi !
Tout ceci normalement vous est familier si vous avez
développé un tant soit peu en Javascript.
Ca marche très bien.
C’est très largement adopté.
Mais…
(car il y a toujours un mais)
(et là il y en a plusieurs).
The Spaghetti Incident
Aka : « C’est normal que ton code
finisse avec une indentation de 658
espaces ? – Ouais.)
The spaghetti incident
Prenons un exemple concret :
Un script doit lire un document JSON en Ajax,
l’analyser, récupérer une url dans ce document, puis
la récupérer et afficher son contenu.
(et pour tricher un peu on va se reposer sur jQuery)
The spaghetti incident
On commence donc par récupérer ce flux JSON :
The spaghetti incident
Oui mais on n’a pas géré le fait que ce document soit
inaccessible ou du JSON mal formé !
The spaghetti incident
Il est donc temps d’aller récupérer l’url contenue dans
le document JSON (en gérant aussi les erreurs) :
The spaghetti incident
Le code précédent est sur le point, si ce n’est déjà
fait, d’obtenir le précieux badge « Spaghetti code »
Donc un code difficile à lire, ou tout est plus ou moins
embrouillé ressemblant à un plat de spaghetti !
(miam)
Is it Async or Sync or potato ?
Aka : « C’est normal que l’ordre de tes
callbacks ne soit pas toujours le même
? – Ouais.)
Async or not async ?
On a vu précédemment que :
Affichera :
1 … 3 … 2 … 4
Async or not async ?
Donc dans notre exemple précédent (épuré de la
gestion des erreurs) :
Affichera :
1 … 4 … 2 … 3
Async or not async ?
Seulement, un développeur bien élevé sait que les
ressources sont chères et souhaite donc stocker l’url
dans le document JSON en mémoire pour ne pas
provoquer un appel $.ajax a chaque évènement, non
?
Alors, allons-y !
Async or not async ?
Async or not async ?
Lors de la première exécution du script précédent,
nous gardons l’ordre :
1 … 4 … 2a … 3
L’url à récupérer contenue dans le doc JSON est
alors sauvegardée dans la variable url_a_recuperer.
=> Cas a (voir après)
Async or not async ?
Lors des appels suivants, nous obtiendrons l’ordre :
1 … 2b … 4 … 3
=> Cas b (voir après)
Async or not async ?
Asynchrone
Synchrone
On ne lit que le code
synchrone :
1 … (2b si cas b) … 4
PUIS le code
asynchrone
(2a si cas a) … 3
(Vous l’avez ?)
(Sinon, recommencez)
(Si, si !)
Synchroniser l’asynchrone ?
Aka : « On y va à 3 ou on compte 1 …
2 … 3 et là on y va ? – Ouais.)
Synchroniser l’asynchrone
Autre problème, autre exemple :
Nous souhaitons exécuter un callback quand
plusieurs opérations asynchrones sont effectuées ;
en l’occurrence :
• Récupérer les 10 derniers tweets de l’utilisateur
(get_tweets)
• Récupérer ses amis Facebook (get_friends)
• Récupérer les projets Github de l’utilisateur (get_projects)
Synchroniser l’asynchrone
On définit 3 fonctions responsables de chaque tâche
:
Oui, à peu près hein.
Synchroniser l’asynchrone
Chacune de ces fonctions fait appel à une API
externe qui peut prendre un temps indéfini à
répondre.
Chacune de ces fonction peut générer une erreur à
tout moment.
Nous devons pourtant synchroniser tout ça …
Synchroniser l’asynchrone
La solution va donc être de définir une fonction de
vérification pour vérifier si tout est récupéré …
Puis d’appeler cette fonction dans chaque callback
de succès …
Synchroniser l’asynchrone
Ici aussi, la solution marche, est répandue mais n’est
pas très élégante :
• La lisibilité du code est complexifiée
• La taille du code est exponentielle au nombre de
fonctions asynchrones à appeler
Bon, vous voyez ou je veux en venir
?
Y’a mieux !
Les Promesses !
Aka : « On avait pas dit point
Toubon, toussa ?
Donc Promises non ? – Ouais.)
Commençons par préciser que c’est une
fonctionnalité ECMAScript 6 (es6), donc pas
disponible de partout.
http://caniuse.com/#feat=promises
Mais … parce que y’a … (hein ? Quoi ?, ha ok,
pardon).
Les Promises
Les Promises
Il existe des (beaucoup) Polyfills pour browser ou node :
• es6-promise
• promise-polyfill
• bluebird
• Q
• Promises, Promises
• Etc, etc, etc.
A mon avis (que personne n’a demandé), bluebird est le meilleur.
Enfin, io.js gère les promises nativement.
Les Promises
Alors les Promises, c’est quoi ?
Les Promises
Au lieu de définir des fonctions avec callbacks en cas
de succès ou d’erreur …
On va définir des promesses.
Ces promesses respecteront une interface
commune que tout le monde peut utiliser
de manière identique.
« Les promesses n’engagent que ceux qui les écoutent. »
J. Chirac
Les Promises
Ces promesses pourront être soit (OU) :
• En cours de réalisation (pending)
• Tenues (fulfilled)
• Non tenues (rejected)
Les Promises
Ces promesses pourront être à la fois (ET) :
• Synchronisées
• Enchainées
• Ordonnées
Les Promises
C’est beau vu comme ça.
Mais concrètement ?
Promises/A+
Une Promise est un object.
Comme tout en Javascript.
(Un petit rappel de temps en temps ne fait pas de mal)
Commençons par « la base », l’implémentation de la
spécification Promises/A+
Promises/A+
Son constructeur prend comme un argument une
fonction dont le prototype est :
f( {Function} setFulfilled , {Function} setRejected )
Son rôle est de tenir cette promesse. ()
Promises/A+
Si la promesse est tenue, elle devra alors appeler
setFulfilled
Sinon, elle devra appeler
setRejected
Promises/A+
L’objet maPromesse est désormais une Promise que
l’on peut attendre grâce à sa méthode then qui a le
prototype suivant :
Promise.prototype.then(
[{Function} onFulfilled],
[{Function] onRejected]
)
Promises/A+
Promises/A+
Adaptons notre précédent exemple (aller chercher et
analyser un document JSON) :
Nous avons désormais une fonction
recupere_mon_json qui retourne une promise dont la
promesse est le document JSON analysé.
Promises/A+
Nous pouvons donc l’utiliser comme n’importe quelle
Promise :
Bon, ok. Comme ça, ça n’a pas l’air de changer
grand-chose. Mais … (oui, je sais).
Promises/A+
Les spécifications des Promises précisent des points
particulièrement intéressants :
Relax ! C’est expliqué dans les slides suivante
Promises/A+
La méthode .then() retourne elle-même une nouvelle
Promise !
Autrement dit, nous pouvons dans notre exemple
enchainer deux Promises : celle de la récupération
du JSON et celle de la récupération de l’url.
Promises/A+
Créons une nouvelle Promise pour la récupération de
l’URL :
Promises/A+
Nous pouvons donc désormais réécrire le script sans
faire un magnifique Spaghetti code !
Promises/A+
Avantage 1 :
Le code est bien plus lisible.
Pas convaincu ?
Imaginez que nous ayons pas 2 requêtes Ajax à
enchainer mais 6.
D’un coté une pyramide d’indentation de 6 niveaux.
De l’autre juste
.then(func1).then(func2).then(func3)…
Promises/A+
Avantage 2 :
Les erreurs ne sont gérées qu’à un seul endroit : au dernier .then()
La première Promise non tenue, quelle qu’elle soit « zappera » alors la
suite du processus jusqu’au dernier .then() !
Rappelez-vous la spécification :
Comme nous avons enchainé des .then(func()) nous n’avons spécifié
que le premier argument de Promise.prototype.then(
[{Function} onFulfilled],
[{Function] onRejected]
)
Sauf pour le dernier .then(). CQFD.
Promises/A+
Avantage 3 :
Il est possible de définir plusieurs .then() pour une
même promise comme on le ferait pour des
évènements.
Il est donc possible de définir plusieurs fonctions
(pour les promesses tenues ou non tenues).
Mais les spécifications des Promises de es6 vont
_beaucoup_ plus loin !
Et là, ça gère sa race.
(A ce stade, le lecteur peut ne pas comprendre la pauvreté de cette blague)
Reprenons notre exemple de 3 fonctionnalités
asynchrones devant être synchronisées :
Promises es6
Si ces trois fonctions sont « Promisifiées » (voir slides
précédentes), la fonction Promise.all() nous permet
de gérer automatiquement la concurrence.
Promises es6
Promise.all( {Array} promisesList ) => Promise
Cette fonction prend comme argument un Array de
Promise, et retourne une nouvelle Promise.
Cette nouvelle Promise sera :
• En attente (pending) en attendant que toute les
promises du tableau en argument soient tenues ;
• Tenue (fulFilled) si l’ensemble des promises du
tableau en argument on été tenues ;
• Non-tenue (rejected) dès que l’une des promises
du tableau en argument n’est pas tenue.
Promises es6
Si la nouvelle Promise est tenue
La fonction onFulfilled reçoit comme argument un
tableau correspondant aux valeurs passées à la
fonction, en respectant l’ordre des promises dans le
tableau initial.
Promises es6
Si la nouvelle Promise n’est pas tenue
La fonction onRejected reçoit comme argument
l’erreur renvoyée par la première promise non tenue
qui a provoqué cet état.
Promises es6
Dans notre exemple, le code sera donc refactorisé de
cette manière :
Promises es6
Quand même beaucoup plus élégant, non ?
Les Promises offrent également une autre manière
de gérer une liste de promises : La fonction race()
(C’est bon, vous l’avez la blague nulle ?)
Promises es6
Promise.all( {Array} promisesList ) => Promise
De la même manière que all(), race() va lancer la
résolution des Promises passées en argument et
retourner une promise.
Si la nouvelle Promise est tenue
La fonction onFulfilled reçoit comme argument la
valeur passée à la fonction setFulfilled de la
première Promise tenue.
Promises es6
Si la nouvelle Promise n’est pas tenue
La fonction onRejected reçoit comme argument
l’erreur renvoyée par la première promise non tenue.
Promises es6

More Related Content

What's hot

Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Julien Jakubowski
 
Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieur
Fredy Fadel
 
Présentation de ECMAScript 6
Présentation de ECMAScript 6Présentation de ECMAScript 6
Présentation de ECMAScript 6
Julien CROUZET
 
Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech days
Jean-Pierre Vincent
 

What's hot (20)

Javascript
JavascriptJavascript
Javascript
 
Javascript proprement
Javascript proprementJavascript proprement
Javascript proprement
 
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
 
Javascript pour les Développeurs WEB
Javascript pour les Développeurs WEBJavascript pour les Développeurs WEB
Javascript pour les Développeurs WEB
 
Javascript un langage supérieur
Javascript un langage supérieurJavascript un langage supérieur
Javascript un langage supérieur
 
Introduction à React
Introduction à ReactIntroduction à React
Introduction à React
 
Présentation de ECMAScript 6
Présentation de ECMAScript 6Présentation de ECMAScript 6
Présentation de ECMAScript 6
 
Présentation JavaScript
Présentation JavaScriptPrésentation JavaScript
Présentation JavaScript
 
Spring Batch ParisJUG
Spring Batch ParisJUG Spring Batch ParisJUG
Spring Batch ParisJUG
 
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
 
La programmation fonctionnelle en javascript / PF
La programmation fonctionnelle en javascript / PFLa programmation fonctionnelle en javascript / PF
La programmation fonctionnelle en javascript / PF
 
Ajax - GTI780 & MTI780 - ETS - A08
Ajax - GTI780 & MTI780 - ETS - A08Ajax - GTI780 & MTI780 - ETS - A08
Ajax - GTI780 & MTI780 - ETS - A08
 
Javascript Json artchitecture
Javascript  Json artchitecture Javascript  Json artchitecture
Javascript Json artchitecture
 
Function oop - bonnes pratiques ms tech days
Function   oop - bonnes pratiques ms tech daysFunction   oop - bonnes pratiques ms tech days
Function oop - bonnes pratiques ms tech days
 
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expertCocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
 
Les Promises en Javascript
Les Promises en JavascriptLes Promises en Javascript
Les Promises en Javascript
 
Patterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScriptPatterns et bonnes pratiques autour de JavaScript
Patterns et bonnes pratiques autour de JavaScript
 
Requêtes HTTP synchrones et asynchrones
Requêtes HTTPsynchrones et asynchronesRequêtes HTTPsynchrones et asynchrones
Requêtes HTTP synchrones et asynchrones
 
Cours php
Cours phpCours php
Cours php
 
Les données transitoires (transients) vous veulent du bien
Les données transitoires (transients) vous veulent du bienLes données transitoires (transients) vous veulent du bien
Les données transitoires (transients) vous veulent du bien
 

Viewers also liked

Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Promises, Promises: Mastering Async I/O in Javascript with the Promise PatternPromises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Christian Lilley
 

Viewers also liked (10)

Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Promises, Promises: Mastering Async I/O in Javascript with the Promise PatternPromises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
 
Avoiding callback hell with promises
Avoiding callback hell with promisesAvoiding callback hell with promises
Avoiding callback hell with promises
 
JavaScript Promise
JavaScript PromiseJavaScript Promise
JavaScript Promise
 
"How to use Linkedin to shake your sales strategy" by Bastien Marduel
"How to use Linkedin to shake your sales strategy" by Bastien Marduel"How to use Linkedin to shake your sales strategy" by Bastien Marduel
"How to use Linkedin to shake your sales strategy" by Bastien Marduel
 
Promises, Promises
Promises, PromisesPromises, Promises
Promises, Promises
 
Le pitch qui nous a permis de lever 500 000 €
Le pitch qui nous a permis de lever 500 000 €Le pitch qui nous a permis de lever 500 000 €
Le pitch qui nous a permis de lever 500 000 €
 
L'Art du pitch
L'Art du pitchL'Art du pitch
L'Art du pitch
 
Beeye - Evolution du pitch
Beeye - Evolution du pitch Beeye - Evolution du pitch
Beeye - Evolution du pitch
 
Comment rédigez un contenu impactant
Comment rédigez un contenu impactantComment rédigez un contenu impactant
Comment rédigez un contenu impactant
 
Digital Business Model Stratégie - ESCEN Paris
Digital Business Model Stratégie - ESCEN ParisDigital Business Model Stratégie - ESCEN Paris
Digital Business Model Stratégie - ESCEN Paris
 

Similar to Promises Javascript

Chouette! Encore un bug!
Chouette! Encore un bug!Chouette! Encore un bug!
Chouette! Encore un bug!
AgileCoach.net
 
Ajax et Accessibilite
Ajax et AccessibiliteAjax et Accessibilite
Ajax et Accessibilite
mikeh
 

Similar to Promises Javascript (20)

Cours JavaScript.ppt
Cours JavaScript.pptCours JavaScript.ppt
Cours JavaScript.ppt
 
Spring 3 en production
Spring 3 en productionSpring 3 en production
Spring 3 en production
 
Nouveautés Java 9-10-11
Nouveautés Java 9-10-11Nouveautés Java 9-10-11
Nouveautés Java 9-10-11
 
Javascript as a first programming language : votre IC prête pour la révolution !
Javascript as a first programming language : votre IC prête pour la révolution !Javascript as a first programming language : votre IC prête pour la révolution !
Javascript as a first programming language : votre IC prête pour la révolution !
 
Rapport tp2 j2ee
Rapport tp2 j2eeRapport tp2 j2ee
Rapport tp2 j2ee
 
Backday xebia - Chercher la performance efficacement
Backday xebia - Chercher la performance efficacement Backday xebia - Chercher la performance efficacement
Backday xebia - Chercher la performance efficacement
 
Chouette! Encore un bug! Agile Tour 2012
Chouette! Encore un bug! Agile Tour 2012Chouette! Encore un bug! Agile Tour 2012
Chouette! Encore un bug! Agile Tour 2012
 
Web API & Cache, the HTTP way - Ippevent 10 Juin 2014
Web API & Cache, the HTTP way - Ippevent 10 Juin 2014Web API & Cache, the HTTP way - Ippevent 10 Juin 2014
Web API & Cache, the HTTP way - Ippevent 10 Juin 2014
 
Tutoriel java
Tutoriel javaTutoriel java
Tutoriel java
 
Les applications réactives, un nouveau paradigme pour relever les défis de l'...
Les applications réactives, un nouveau paradigme pour relever les défis de l'...Les applications réactives, un nouveau paradigme pour relever les défis de l'...
Les applications réactives, un nouveau paradigme pour relever les défis de l'...
 
Mysql
MysqlMysql
Mysql
 
Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...
Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...
Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...
 
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et JenkinsBuild automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
 
Docker en Production (Docker Paris)
Docker en Production (Docker Paris)Docker en Production (Docker Paris)
Docker en Production (Docker Paris)
 
Chouette! Encore un bug!
Chouette! Encore un bug!Chouette! Encore un bug!
Chouette! Encore un bug!
 
Scalabilité et haute performance d'application PHP légacy
Scalabilité et haute performance d'application PHP légacy Scalabilité et haute performance d'application PHP légacy
Scalabilité et haute performance d'application PHP légacy
 
Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...
Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...
Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...
 
Ajax et Accessibilite
Ajax et AccessibiliteAjax et Accessibilite
Ajax et Accessibilite
 
Performance et optimisation de PrestaShop
Performance et optimisation de PrestaShopPerformance et optimisation de PrestaShop
Performance et optimisation de PrestaShop
 
Formation java script
Formation java scriptFormation java script
Formation java script
 

Promises Javascript

  • 3. Commençons par analyser en détail comment Javascript gère un problème vieux comme le développement : Le fonctionnement asynchrone.
  • 4. Event Loop • Javascript est essentiellement un langage asynchrone (en opposition à « procédural ») • On utilise souvent cette structure évènementielle en définissant des « écouteurs » d’évènements (Par exemple avec l’event object model  )
  • 6. Event Loop L’ avantage du modèle est de ne pas bloquer le processus principal (comme par exemple le navigateur ou votre programme Node.js) pendant l’attente de l’évènement.
  • 7. Event Loop En développement, on appelle une opération synchrone lorsqu’elle est exécutée « telle que l’on peut la lire » (barbarisme, mais bon). Prenons l’exemple en PHP de la récupération du contenu (HTML) d’une url :
  • 9. Event Loop Ce script va être exécuté ligne par ligne et afficher le résultat suivant : On lance Etape 2 0.25 Le temps écoulé pendant le téléchargement de l’url (0,25 seconde) correspond également au temps pendant lequel le programme est bloqué. Si le téléchargement prend plusieurs secondes (voir plus), c’est donc problématique.
  • 10. Event Loop Dans le cadre d’une application avec une interface graphique (par exemple), on ne pas peut se le permettre ! On a donc créé les threads.
  • 11. Event Loop Sans rentrer dans les détails, il s’agit de créer une unité d’exécution parallèle à notre programme qui aurait ici le noble rôle d’attendre un évènement ou d’effectuer une tâche sans bloquer notre interface.
  • 12. Event Loop Contrairement à beaucoup d’autres langages Javascript n’a pas de mécanismes de gestion des threads, et pour cause, il n’est exécuté que dans un seul(*) thread. (*) : Ce n’est pas tout à fait vrai, mais peu importe ici…
  • 13. Event Loop En Javascript, on règle le problème avec une toute autre méthode : L’Event Loop !
  • 14. Event Loop L’Event Loop (la boucle d’évènements, donc) est appelée ainsi puisqu’on peut la conceptualiser avec le pseudo code suivant : TANT_QUE boucle.attend_message() boucle.prochain_message() FIN_TANT_QUE
  • 15. • L’Event Loop est donc une pile de messages où chaque message est une fonction à exécuter. • Les messages sont donc empilés à chaque fois qu’un évènement auquel on a attaché un ou plusieurs callbacks (écouteurs) survient. • Et ils sont donc dépilés (au fur et à mesure) par la boucle d’évènement. Event Loop
  • 16. Event Loop Petit interlude « Loi Toubon » avant d’en arriver à parler de butineurs. • callback: Ecouteur (fonction a exécuter sur un évènement) • message: Fonction empilée lors d’un évènement (callback en attente donc!) • event loop: La boucle d’évènement permanente qui dépile les message. Voilà, ça c’est fait.
  • 17. Event Loop Donc lorsque l’on ajoute le callback suivant : On précise « A chaque fois que l’évènement « resize » intervient sur l’objet window, empile le message replace_elements dans l’event loop.
  • 18. Event Loop Deux points importants !
  • 19. Event Loop Nous avons bien précisé replace_elements et non pas replace_elements() La deuxième notation reviendrait à dire exécute immédiatement la fonction replace_elements puis place sa valeur de retour comme callback de l’évènement. (Ceci représente 10^42 questions sur StackOverflow…)
  • 20. Event Loop(Ceci représente aussi 10^42 questions sur StackOverflow…) Affichera : 1 … 3 … 2 … 4 ! Ne jamais confondre sens de lecture du code et logique d’event loop :
  • 21. Event Loop Enfin, si l’on reprend notre pseudo code : TANT_QUE boucle.attend_message() boucle.prochain_message() FIN_TANT_QUE On remarque que les messages sont exécutés un par un ; il est donc d’usage de faire des callbacks rapides, sous peine de voir nos prochains évènements traités longtemps après être survenu. Et puis ça aussi !
  • 22. Tout ceci normalement vous est familier si vous avez développé un tant soit peu en Javascript. Ca marche très bien. C’est très largement adopté. Mais… (car il y a toujours un mais) (et là il y en a plusieurs).
  • 23. The Spaghetti Incident Aka : « C’est normal que ton code finisse avec une indentation de 658 espaces ? – Ouais.)
  • 24. The spaghetti incident Prenons un exemple concret : Un script doit lire un document JSON en Ajax, l’analyser, récupérer une url dans ce document, puis la récupérer et afficher son contenu. (et pour tricher un peu on va se reposer sur jQuery)
  • 25. The spaghetti incident On commence donc par récupérer ce flux JSON :
  • 26. The spaghetti incident Oui mais on n’a pas géré le fait que ce document soit inaccessible ou du JSON mal formé !
  • 27. The spaghetti incident Il est donc temps d’aller récupérer l’url contenue dans le document JSON (en gérant aussi les erreurs) :
  • 28. The spaghetti incident Le code précédent est sur le point, si ce n’est déjà fait, d’obtenir le précieux badge « Spaghetti code » Donc un code difficile à lire, ou tout est plus ou moins embrouillé ressemblant à un plat de spaghetti ! (miam)
  • 29. Is it Async or Sync or potato ? Aka : « C’est normal que l’ordre de tes callbacks ne soit pas toujours le même ? – Ouais.)
  • 30. Async or not async ? On a vu précédemment que : Affichera : 1 … 3 … 2 … 4
  • 31. Async or not async ? Donc dans notre exemple précédent (épuré de la gestion des erreurs) : Affichera : 1 … 4 … 2 … 3
  • 32. Async or not async ? Seulement, un développeur bien élevé sait que les ressources sont chères et souhaite donc stocker l’url dans le document JSON en mémoire pour ne pas provoquer un appel $.ajax a chaque évènement, non ? Alors, allons-y !
  • 33. Async or not async ?
  • 34. Async or not async ? Lors de la première exécution du script précédent, nous gardons l’ordre : 1 … 4 … 2a … 3 L’url à récupérer contenue dans le doc JSON est alors sauvegardée dans la variable url_a_recuperer. => Cas a (voir après)
  • 35. Async or not async ? Lors des appels suivants, nous obtiendrons l’ordre : 1 … 2b … 4 … 3 => Cas b (voir après)
  • 36. Async or not async ? Asynchrone Synchrone On ne lit que le code synchrone : 1 … (2b si cas b) … 4 PUIS le code asynchrone (2a si cas a) … 3 (Vous l’avez ?) (Sinon, recommencez) (Si, si !)
  • 37. Synchroniser l’asynchrone ? Aka : « On y va à 3 ou on compte 1 … 2 … 3 et là on y va ? – Ouais.)
  • 38. Synchroniser l’asynchrone Autre problème, autre exemple : Nous souhaitons exécuter un callback quand plusieurs opérations asynchrones sont effectuées ; en l’occurrence : • Récupérer les 10 derniers tweets de l’utilisateur (get_tweets) • Récupérer ses amis Facebook (get_friends) • Récupérer les projets Github de l’utilisateur (get_projects)
  • 39. Synchroniser l’asynchrone On définit 3 fonctions responsables de chaque tâche : Oui, à peu près hein.
  • 40. Synchroniser l’asynchrone Chacune de ces fonctions fait appel à une API externe qui peut prendre un temps indéfini à répondre. Chacune de ces fonction peut générer une erreur à tout moment. Nous devons pourtant synchroniser tout ça …
  • 41. Synchroniser l’asynchrone La solution va donc être de définir une fonction de vérification pour vérifier si tout est récupéré … Puis d’appeler cette fonction dans chaque callback de succès …
  • 42. Synchroniser l’asynchrone Ici aussi, la solution marche, est répandue mais n’est pas très élégante : • La lisibilité du code est complexifiée • La taille du code est exponentielle au nombre de fonctions asynchrones à appeler
  • 43. Bon, vous voyez ou je veux en venir ? Y’a mieux !
  • 44. Les Promesses ! Aka : « On avait pas dit point Toubon, toussa ? Donc Promises non ? – Ouais.)
  • 45. Commençons par préciser que c’est une fonctionnalité ECMAScript 6 (es6), donc pas disponible de partout. http://caniuse.com/#feat=promises Mais … parce que y’a … (hein ? Quoi ?, ha ok, pardon). Les Promises
  • 46. Les Promises Il existe des (beaucoup) Polyfills pour browser ou node : • es6-promise • promise-polyfill • bluebird • Q • Promises, Promises • Etc, etc, etc. A mon avis (que personne n’a demandé), bluebird est le meilleur. Enfin, io.js gère les promises nativement.
  • 47. Les Promises Alors les Promises, c’est quoi ?
  • 48. Les Promises Au lieu de définir des fonctions avec callbacks en cas de succès ou d’erreur … On va définir des promesses. Ces promesses respecteront une interface commune que tout le monde peut utiliser de manière identique. « Les promesses n’engagent que ceux qui les écoutent. » J. Chirac
  • 49. Les Promises Ces promesses pourront être soit (OU) : • En cours de réalisation (pending) • Tenues (fulfilled) • Non tenues (rejected)
  • 50. Les Promises Ces promesses pourront être à la fois (ET) : • Synchronisées • Enchainées • Ordonnées
  • 51. Les Promises C’est beau vu comme ça. Mais concrètement ?
  • 52. Promises/A+ Une Promise est un object. Comme tout en Javascript. (Un petit rappel de temps en temps ne fait pas de mal) Commençons par « la base », l’implémentation de la spécification Promises/A+
  • 53. Promises/A+ Son constructeur prend comme un argument une fonction dont le prototype est : f( {Function} setFulfilled , {Function} setRejected ) Son rôle est de tenir cette promesse. ()
  • 54. Promises/A+ Si la promesse est tenue, elle devra alors appeler setFulfilled Sinon, elle devra appeler setRejected
  • 55. Promises/A+ L’objet maPromesse est désormais une Promise que l’on peut attendre grâce à sa méthode then qui a le prototype suivant : Promise.prototype.then( [{Function} onFulfilled], [{Function] onRejected] )
  • 57. Promises/A+ Adaptons notre précédent exemple (aller chercher et analyser un document JSON) : Nous avons désormais une fonction recupere_mon_json qui retourne une promise dont la promesse est le document JSON analysé.
  • 58. Promises/A+ Nous pouvons donc l’utiliser comme n’importe quelle Promise : Bon, ok. Comme ça, ça n’a pas l’air de changer grand-chose. Mais … (oui, je sais).
  • 59. Promises/A+ Les spécifications des Promises précisent des points particulièrement intéressants : Relax ! C’est expliqué dans les slides suivante
  • 60. Promises/A+ La méthode .then() retourne elle-même une nouvelle Promise ! Autrement dit, nous pouvons dans notre exemple enchainer deux Promises : celle de la récupération du JSON et celle de la récupération de l’url.
  • 61. Promises/A+ Créons une nouvelle Promise pour la récupération de l’URL :
  • 62. Promises/A+ Nous pouvons donc désormais réécrire le script sans faire un magnifique Spaghetti code !
  • 63. Promises/A+ Avantage 1 : Le code est bien plus lisible. Pas convaincu ? Imaginez que nous ayons pas 2 requêtes Ajax à enchainer mais 6. D’un coté une pyramide d’indentation de 6 niveaux. De l’autre juste .then(func1).then(func2).then(func3)…
  • 64. Promises/A+ Avantage 2 : Les erreurs ne sont gérées qu’à un seul endroit : au dernier .then() La première Promise non tenue, quelle qu’elle soit « zappera » alors la suite du processus jusqu’au dernier .then() ! Rappelez-vous la spécification : Comme nous avons enchainé des .then(func()) nous n’avons spécifié que le premier argument de Promise.prototype.then( [{Function} onFulfilled], [{Function] onRejected] ) Sauf pour le dernier .then(). CQFD.
  • 65. Promises/A+ Avantage 3 : Il est possible de définir plusieurs .then() pour une même promise comme on le ferait pour des évènements. Il est donc possible de définir plusieurs fonctions (pour les promesses tenues ou non tenues).
  • 66. Mais les spécifications des Promises de es6 vont _beaucoup_ plus loin ! Et là, ça gère sa race. (A ce stade, le lecteur peut ne pas comprendre la pauvreté de cette blague)
  • 67. Reprenons notre exemple de 3 fonctionnalités asynchrones devant être synchronisées : Promises es6
  • 68. Si ces trois fonctions sont « Promisifiées » (voir slides précédentes), la fonction Promise.all() nous permet de gérer automatiquement la concurrence. Promises es6 Promise.all( {Array} promisesList ) => Promise Cette fonction prend comme argument un Array de Promise, et retourne une nouvelle Promise.
  • 69. Cette nouvelle Promise sera : • En attente (pending) en attendant que toute les promises du tableau en argument soient tenues ; • Tenue (fulFilled) si l’ensemble des promises du tableau en argument on été tenues ; • Non-tenue (rejected) dès que l’une des promises du tableau en argument n’est pas tenue. Promises es6
  • 70. Si la nouvelle Promise est tenue La fonction onFulfilled reçoit comme argument un tableau correspondant aux valeurs passées à la fonction, en respectant l’ordre des promises dans le tableau initial. Promises es6
  • 71. Si la nouvelle Promise n’est pas tenue La fonction onRejected reçoit comme argument l’erreur renvoyée par la première promise non tenue qui a provoqué cet état. Promises es6
  • 72. Dans notre exemple, le code sera donc refactorisé de cette manière : Promises es6 Quand même beaucoup plus élégant, non ?
  • 73. Les Promises offrent également une autre manière de gérer une liste de promises : La fonction race() (C’est bon, vous l’avez la blague nulle ?) Promises es6 Promise.all( {Array} promisesList ) => Promise De la même manière que all(), race() va lancer la résolution des Promises passées en argument et retourner une promise.
  • 74. Si la nouvelle Promise est tenue La fonction onFulfilled reçoit comme argument la valeur passée à la fonction setFulfilled de la première Promise tenue. Promises es6
  • 75. Si la nouvelle Promise n’est pas tenue La fonction onRejected reçoit comme argument l’erreur renvoyée par la première promise non tenue. Promises es6