Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TGIF ES6 Promises

TGIF ES6 Promises

Introduction to JS asynchronous programming with Promises.

Check the updated online version:
http://codekult.github.io/tgif-es6-promises

Diego Calderón

March 20, 2015
Tweet

More Decks by Diego Calderón

Other Decks in Programming

Transcript

  1. “Many developers are excited by the promise of better async

    patterns. But it's impossible to effectivily use any abstraction if you don't understand what it's abstracting, and why” @getify
  2. It seems that in JS we can do many things

    at the same time, make a request, set event listeners or cycle through a loop. But really the JS engine is single threaded, an have what is called a run-to-completion behavior.
  3. It's often necessary to do some form of interaction coordination

    between these concurrent "processes", to prevent race conditions or to prevent blocking the event loop. Also don't forget that this single thread is shared with the browser's tasks, as repainting, updating styles and handling user interaction.
  4. All we know callbacks: e l e m e n

    t . a d d E v e n t L i s t e n e r ( ' c l i c k ' , f u n c t i o n ( ) { / / D o s o m e t h i n g w h e n c l i c k } ) ;
  5. They are the most fundamental async pattern in the language,

    and work in a manner called Continuation Passing Style: e l e m e n t . a d d E v e n t L i s t e n e r ( ' c l i c k ' , f u n c t i o n ( ) { s e t T i m e O u t ( f u n c t i o n ( ) { a j a x ( ' / u r l ' , f u n c t i o n ( r e s p o n s e ) { c o n s o l e . l o g ( r e s p o n s e ) ; } ) ; } , 5 0 0 ) ; } ) ;
  6. It seems pretty straightforward, but: c o n s o

    l e . l o g ( ' A ' ) ; e l e m e n t . a d d E v e n t L i s t e n e r ( ' c l i c k ' , f u n c t i o n ( ) { c o n s o l e . l o g ( ' B ' ) ; s e t T i m e O u t ( f u n c t i o n ( ) { a j a x ( ' / u r l ' , f u n c t i o n ( r e s p o n s e ) { c o n s o l e . l o g ( r e s p o n s e ) ; } ) ; c o n s o l e . l o g ( ' C ' ) ; } , 5 0 0 ) ; c o n s o l e . l o g ( ' D ' ) ; } ) ; c o n s o l e . l o g ( ' E ' ) ; / / A , E , B , D , C , r e s p o n s e
  7. Other callback withdraws: Inversion of control. Lack of sequentiality. Lack

    of trustability. Messy functions signature (input and output are mixed).
  8. Callbacks are the fundamental unit of asynchrony in JS, and

    the same as CPS or the different concurrency management patterns, they're very useful. But they're not enough for the evolving landscape of async programming as JS matures.
  9. Promises are a software abstraction that represent (or are the

    placeholder for) the eventual result of an asynchronous operation.
  10. DOM APIs are relying on promises (ServiceWorker, fectch API, Streams).

    Compared to events, doesn't matter when you observe/register the promise. Are better than callbacks in: * Chaining/sequentiality. * Error handling. * Cleaner function signature More elegant code: Comparative example
  11. Some terminology promise - Is an object or function with

    a t h e n method whose behavior conforms to this specification. thenable - Is an object or function that defines a then method. value - Is any legal JS value, including u n d e f i n e d , a thenable, or a promise. reason - Is a value that indicates why a promise was rejected.
  12. Promise states fulfilled - The action relating to the promise

    succeeded. rejected - The action relating to the promise failed. pending - Hasn't fulfilled or rejected yet. settled - Has fulfilled or rejected.
  13. The t h e n method It's at the core

    of the specification and provides a shared common base to all implementations. Also allows Promises/A+ implementations to "assimilate" nonconformant implementations with reasonable then methods.
  14. The Good - Complete and Powerful. Used in Angular.js and

    written by one of the A+ spec's author. Q
  15. The Bad …but not so bad - Simple but lightweight.

    There is a based on a subset of this library. rsvp.js polyfill
  16. Create a promise: v a r m y P r

    o m i s e = n e w P r o m i s e ( f u n c t i o n ( r e s o l v e , r e j e c t ) { / / D o a t h i n g , p o s s i b l y a s y n c , t h e n … i f ( / * s u c c e s s * / ) { r e s o l v e ( v a l u e ) ; } e l s e { r e j e c t ( r e a s o n ) ; / / I t ' s r e c o m m e n d e d t o u s e a n ` E r r o r ` o b j e c t a s r e a s o } } ) ;
  17. Consume a promise: m y P r o m i

    s e . t h e n ( f u n c t i o n ( v a l u e ) { / * f u l f i l l m e n t * / } , f u n c t i o n ( r e a s o n ) { / * r e j e c t i o n * / } ) ;
  18. Promisifying X M L H t t p R e

    q u e s t f u n c t i o n h t t p G e t ( u r l ) { r e t u r n n e w P r o m i s e ( f u n c t i o n ( r e s o l v e , r e j e c t ) { v a r r e q u e s t = n e w X M L H t t p R e q u e s t ( ) ; r e q u e s t . o n r e a d y s t a t e c h a n g e = f u n c t i o n ( ) { i f ( t h i s . s t a t u s = = = 2 0 0 ) { / / S u c c e s s r e s o l v e ( t h i s . r e s p o n s e ) ; } e l s e { / / S o m e t h i n g w e n t w r o n g ( 4 0 4 e t c . ) r e j e c t ( n e w E r r o r ( t h i s . s t a t u s T e x t ) ) ; } } r e q u e s t . o n e r r o r = f u n c t i o n ( ) { r e j e c t ( n e w E r r o r ( ' X M L H t t p R e q u e s t E r r o r : ' + t h i s . s t a t u s T e x t ) ) ; } ; r e q u e s t . o p e n ( ' G E T ' , u r l ) ;
  19. Using it: h t t p G e t (

    ' h t t p : / / e x a m p l e . c o m / f i l e . t x t ' ) . t h e n ( f u n c t i o n ( v a l u e ) { c o n s o l e . l o g ( ' C o n t e n t s : ' + v a l u e ) ; } , f u n c t i o n ( r e a s o n ) { c o n s o l e . e r r o r ( ' S o m e t h i n g w e n t w r o n g ' , r e a s o n ) ; } ) ;
  20. Chaining: h t t p G e t ( '

    s t o r y . j s o n ' ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { r e t u r n J S O N . p a r s e ( r e s p o n s e ) ; } ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { c o n s o l e . l o g ( " P a r s e d J S O N : " , r e s p o n s e ) ; } ) ;
  21. Chaining thenables: h t t p G e t (

    ' / g e t B o o k s C o l l e c t i o n ' ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { h t t p G e t ( ' / g e t B o o k s C o l l e c t i o n / ' + r e s p o n s e [ 0 ] . i d ) ; } ) . t h e n ( f u n c t i o n ( b o o k D a t a ) { c o n s o l e . l o g ( ' F i r s t b o o k : ' + b o o k D a t a . n a m e ) ; } ) ;
  22. Error handling: Using rejection callback h t t p G

    e t ( ' / u r l ' ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { / / S u c c e s s } , f u n c t i o n ( e r r ) { / / R e j e c t i o n c a l l b a c k c o n s o l e . e r r o r ( ' E r r o r : ' , e r r ) ; } ) ;
  23. Using c a t c h clausure: h t t

    p G e t ( ' / u r l ' ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { / / H a n d l e r e s p o n s e } ) . c a t c h ( f u n c t i o n ( ) { / / H a n d l e e r r o r } ) ;
  24. It's like: h t t p G e t (

    ' / u r l ' ) . t h e n ( f u n c t i o n ( r e s p o n s e ) { / / H a n d l e r e s p o n s e } ) . t h e n ( u n d e f i n e d , f u n c t i o n ( ) { / / H a n d l e e r r o r } ) ;
  25. P r o m i s e . a l

    l "Gate" All the promises you pass in must fulfill for the returned promise to fulfill. If fulfilled, returns an array with all the promises values. If rejected, returns the first promise rejection reason. P r o m i s e . r a c e "Latch" Only the first promise to resolve (fulfillment or rejection) "wins". It returns its fulfillment value or rejection reason.
  26. v a r p 1 = P r o m

    i s e . r e s o l v e ( 4 2 ) ; v a r p 2 = P r o m i s e . r e s o l v e ( " H e l l o W o r l d " ) ; v a r p 3 = P r o m i s e . r e j e c t ( " O o p s " ) ; P r o m i s e . r a c e ( [ p 1 , p 2 , p 3 ] ) . t h e n ( f u n c t i o n ( m s g ) { c o n s o l e . l o g ( m s g ) ; / / 4 2 } ) ; P r o m i s e . a l l ( [ p 1 , p 2 , p 3 ] ) . c a t c h ( f u n c t i o n ( e r r ) { c o n s o l e . e r r o r ( e r r ) ; / / " O o p s " } ) ; P r o m i s e . a l l ( [ p 1 , p 2 ] ) . t h e n ( f u n c t i o n ( m s g s ) { c o n s o l e . l o g ( m s g s ) ; / / [ 4 2 , " H e l l o W o r l d " ]
  27. Also there are anti-patterns: Recurrent nested promises. Swallowed errors. Messy

    chained promises (the revenge of the callback hell). . More promise anti-patterns
  28. Generators are a special kind of function that can be

    suspended and resumed (with the y i e l d operator). They are similar to other languages' , and allow to expressing async flow control in a sequential, synchronous- looking fashion. coroutines
  29. Regarding to the event loop, don't make it wait. JavaScript

    is single threaded, but we can use events, callbacks and CPS to deal with this. Promises allows us to create more sophisticated async patterns. ES6 implements promises according to the Promises/A+ spec. Some newest DOM APIs are based on the use of promises. The basic use of promises is easy to aboard, but they underhood mechanism is sort of complicated. Generators empowers promises, giving us a sequential- like flow.
  30. Webography Concurrency model and Event Loop The JavaScript Event Loop:

    Explained What the heck is the event loop anyway? JavaScript Promises: There and back again ECMAScript 6 promises: Foundations ECMAScript 6 promises: The API No promises: Async JS with only generators Promises and Generators: Control flow utopia YDKJS: Async & Performance
  31. Q&A