SlideShare une entreprise Scribd logo
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

Contenu connexe

Tendances (20)

PDF
Javascript
Soufiene Bouzid
 
PPTX
Javascript proprement
Guillaume Collic
 
PDF
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Julien Jakubowski
 
PDF
Javascript pour les Développeurs WEB
Abbes Rharrab
 
PPTX
Javascript un langage supérieur
Fredy Fadel
 
PDF
Introduction à React
Thibault Martinez
 
PPTX
Présentation de ECMAScript 6
Julien CROUZET
 
PPTX
Présentation JavaScript
tarkan_
 
PDF
Spring Batch ParisJUG
Julien Jakubowski
 
PDF
CocoaHeads Rennes #13 : Magical Record
CocoaHeadsRNS
 
PDF
La programmation fonctionnelle en javascript / PF
C...L, NESPRESSO, WAFAASSURANCE, SOFRECOM ORANGE
 
PDF
Ajax - GTI780 & MTI780 - ETS - A08
Claude Coulombe
 
PDF
Javascript Json artchitecture
zaghir
 
PDF
Function oop - bonnes pratiques ms tech days
Jean-Pierre Vincent
 
PDF
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeadsRNS
 
PPTX
Les Promises en Javascript
Benoit Zohar
 
ODP
Patterns et bonnes pratiques autour de JavaScript
Microsoft Technet France
 
PPTX
Requêtes HTTP synchrones et asynchrones
Abdoulaye Dieng
 
PDF
Cours php
Narûtö Bàl'Sèm
 
PDF
Les données transitoires (transients) vous veulent du bien
Julio Potier
 
Javascript
Soufiene Bouzid
 
Javascript proprement
Guillaume Collic
 
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Julien Jakubowski
 
Javascript pour les Développeurs WEB
Abbes Rharrab
 
Javascript un langage supérieur
Fredy Fadel
 
Introduction à React
Thibault Martinez
 
Présentation de ECMAScript 6
Julien CROUZET
 
Présentation JavaScript
tarkan_
 
Spring Batch ParisJUG
Julien Jakubowski
 
CocoaHeads Rennes #13 : Magical Record
CocoaHeadsRNS
 
La programmation fonctionnelle en javascript / PF
C...L, NESPRESSO, WAFAASSURANCE, SOFRECOM ORANGE
 
Ajax - GTI780 & MTI780 - ETS - A08
Claude Coulombe
 
Javascript Json artchitecture
zaghir
 
Function oop - bonnes pratiques ms tech days
Jean-Pierre Vincent
 
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeadsRNS
 
Les Promises en Javascript
Benoit Zohar
 
Patterns et bonnes pratiques autour de JavaScript
Microsoft Technet France
 
Requêtes HTTP synchrones et asynchrones
Abdoulaye Dieng
 
Les données transitoires (transients) vous veulent du bien
Julio Potier
 

En vedette (10)

PDF
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Christian Lilley
 
PDF
Avoiding callback hell with promises
TorontoNodeJS
 
PDF
JavaScript Promise
Joseph Chiang
 
PDF
"How to use Linkedin to shake your sales strategy" by Bastien Marduel
TheFamily
 
PPTX
Promises, Promises
Domenic Denicola
 
PPTX
Le pitch qui nous a permis de lever 500 000 €
Swapcard
 
PDF
L'Art du pitch
Dany Baillargeon
 
PDF
Beeye - Evolution du pitch
Beeye
 
PPTX
Comment rédigez un contenu impactant
DMPROCONSEIL
 
PDF
Digital Business Model Stratégie - ESCEN Paris
Nicolas Bariteau
 
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Christian Lilley
 
Avoiding callback hell with promises
TorontoNodeJS
 
JavaScript Promise
Joseph Chiang
 
"How to use Linkedin to shake your sales strategy" by Bastien Marduel
TheFamily
 
Promises, Promises
Domenic Denicola
 
Le pitch qui nous a permis de lever 500 000 €
Swapcard
 
L'Art du pitch
Dany Baillargeon
 
Beeye - Evolution du pitch
Beeye
 
Comment rédigez un contenu impactant
DMPROCONSEIL
 
Digital Business Model Stratégie - ESCEN Paris
Nicolas Bariteau
 
Publicité

Similaire à Promises Javascript (20)

PPT
Cours JavaScript.ppt
PROFPROF11
 
PDF
Spring 3 en production
Julien Dubois
 
PDF
Nouveautés Java 9-10-11
Mahamadou TOURE, Ph.D.
 
PDF
web-avance-jssvghjjjjjjkkkkhjjjjjkrtyujj
CdricMboutou
 
PPTX
Javascript as a first programming language : votre IC prête pour la révolution !
VISEO
 
PDF
Rapport tp2 j2ee
Soukaina Boujadi
 
PDF
Backday xebia - Chercher la performance efficacement
Publicis Sapient Engineering
 
PPTX
Chouette! Encore un bug! Agile Tour 2012
AgileCoach.net
 
PDF
Java apprendre les fondamentaux - skander nabli
ssuserdc0ca3
 
PDF
Web API & Cache, the HTTP way - Ippevent 10 Juin 2014
Ippon
 
PDF
Tutoriel java
Kalilou DIABY
 
PPT
Les applications réactives, un nouveau paradigme pour relever les défis de l'...
Fabrice Croiseaux
 
PPT
Mysql
mustaphagren
 
PPTX
javascript cours developpement nbhdjcbhdcjbn
SaLma905325
 
PDF
Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...
Nicolas Silberman
 
KEY
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
CocoaHeads France
 
PDF
Docker en Production (Docker Paris)
Jérôme Petazzoni
 
PPTX
Chouette! Encore un bug!
AgileCoach.net
 
PPTX
Scalabilité et haute performance d'application PHP légacy
Arnaud LEMAIRE
 
PDF
Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...
sametmax
 
Cours JavaScript.ppt
PROFPROF11
 
Spring 3 en production
Julien Dubois
 
Nouveautés Java 9-10-11
Mahamadou TOURE, Ph.D.
 
web-avance-jssvghjjjjjjkkkkhjjjjjkrtyujj
CdricMboutou
 
Javascript as a first programming language : votre IC prête pour la révolution !
VISEO
 
Rapport tp2 j2ee
Soukaina Boujadi
 
Backday xebia - Chercher la performance efficacement
Publicis Sapient Engineering
 
Chouette! Encore un bug! Agile Tour 2012
AgileCoach.net
 
Java apprendre les fondamentaux - skander nabli
ssuserdc0ca3
 
Web API & Cache, the HTTP way - Ippevent 10 Juin 2014
Ippon
 
Tutoriel java
Kalilou DIABY
 
Les applications réactives, un nouveau paradigme pour relever les défis de l'...
Fabrice Croiseaux
 
javascript cours developpement nbhdjcbhdcjbn
SaLma905325
 
Industrialisation des environnements de dev avec Puppet et Amazon (mais en fa...
Nicolas Silberman
 
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
CocoaHeads France
 
Docker en Production (Docker Paris)
Jérôme Petazzoni
 
Chouette! Encore un bug!
AgileCoach.net
 
Scalabilité et haute performance d'application PHP légacy
Arnaud LEMAIRE
 
Présentation de WAMP.ws, le protocole pour faire du PUB/SUB et RPC over Webso...
sametmax
 
Publicité

Dernier (11)

PPTX
Soutanece Stage Pfe Développement Web et Multimédia
YassineMyara
 
PDF
Katalog VRF Clivet vrf technology(1).pdf
MehfoozAli19
 
PDF
Présentation UCOPIA et ses fonctionnalités
ZakariaRAHOUI2
 
PDF
Google Remote Procedure Call Web Service
SOUFIANE MOUHTARAM
 
PDF
Généralités sur balisage (Tagging) en git
SOUFIANE MOUHTARAM
 
PDF
Communication entre les conteneurs docker dans diff réseaux
SOUFIANE MOUHTARAM
 
PDF
Rapport de Stage Fin D’étude - Développement Web et Multimédia
YassineMyara
 
PDF
CHAPITRE 5_Déplacement des données DBA.pdf
houcemswissi1
 
PPTX
Stage PFE en Développement Web – Projet de Vidéosurveillance IP
Abderahman Ouzzani chahdie
 
PDF
Circuit Breaker pattern avec Resilience4j
SOUFIANE MOUHTARAM
 
PDF
CHAPITRE1_Architecture du Serveur Oracle.pdf
houcemswissi1
 
Soutanece Stage Pfe Développement Web et Multimédia
YassineMyara
 
Katalog VRF Clivet vrf technology(1).pdf
MehfoozAli19
 
Présentation UCOPIA et ses fonctionnalités
ZakariaRAHOUI2
 
Google Remote Procedure Call Web Service
SOUFIANE MOUHTARAM
 
Généralités sur balisage (Tagging) en git
SOUFIANE MOUHTARAM
 
Communication entre les conteneurs docker dans diff réseaux
SOUFIANE MOUHTARAM
 
Rapport de Stage Fin D’étude - Développement Web et Multimédia
YassineMyara
 
CHAPITRE 5_Déplacement des données DBA.pdf
houcemswissi1
 
Stage PFE en Développement Web – Projet de Vidéosurveillance IP
Abderahman Ouzzani chahdie
 
Circuit Breaker pattern avec Resilience4j
SOUFIANE MOUHTARAM
 
CHAPITRE1_Architecture du Serveur Oracle.pdf
houcemswissi1
 

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