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

Avoiding Callback hell with Async.JS library and Promises

Joe Palala
February 05, 2016

Avoiding Callback hell with Async.JS library and Promises

My first slide deck on advanced javascript - avoiding callback hell using asyncjs library and promises libraries. Presented at ManilaJS Feb 2016 meetup

Joe Palala

February 05, 2016
Tweet

Other Decks in Technology

Transcript

  1. CALLBACK HELL (PYRAMID OF DOOM) / / n e s

    t e d c a l l b a c k s = p y r a m i d o f d o o m v a r f s = r e q u i r e ( ' f s ' ) ; v a r p a r s e S t r i n g = r e q u i r e ( ' x m l 2 j s ' ) . p a r s e S t r i n g ; f s . r e a d F i l e ( " f i l e n a m e " , ' u t f 8 ' , f u n c t i o n ( e r r , f i l e ) { i f ( e r r ) { t h r o w e r r ; } p a r s e S t r i n g ( f i l e , f u n c t i o n ( e r r , r e s u l t ) { i f ( e r r ) { t h r o w e r r ; } i f ( ! ! r e s u l t ) { f s . w r i t e F i l e ( ' / t m p / ' + r e s u l t . t i t l e + ' . j s o n ' , r e s u l t , f u n c t i o n ( e r r , r e s u l t ) { i f ( ! e r r ) { c o n s o l e . l o g ( ' F i l e w r i t t e n t o ' + ' / t m p / ' + r e s u l t . t i t l e + ' . j s o n ' } ) ; } e l s e {
  2. WHY NOT CALLBACKS WITHIN CALLBACKS? Avoid Tight coupling Difficult to

    read Hard to Test v a r d r e a m W i t h i n A D r e a m C a l l b a c k = f u n c t i o n ( e r r , d r e a m ) { i f ( e r r ) { c o n s o l e . l o g ( ' S n a p o u t o f d r e a m w i t h i n a d r e a m ' + d r e a m ) ; } e l s e { / / k e e p d r e a m i n g ! r e t u r n c a l l b a c k ( n u l l , ' d r e a m F o r e v e r ' ) ; } } ; v a r f i r s t D r e a m C a l l b a c k = f u n c t i o n ( e r r , d r e a m R e s u l t ) { i f ( e r r ) { c o n s o l e . l o g ( ' S n a p o u t ' ) ; / / s n a p b a c k t o r e a l w o r l d i f s o m e t h i n g s n o t r i g h t } e l s e { d r e a m W i t h i n A D r e a m C a l l b a c k ( n u l l , d r e a m R e s u l t ) ; } } ; f u n c t i o n f i r s t D r e a m ( d r e a m ) { d r e a m S e c o n d D r e a m ( e r r , f i r s t D r e a m C a l l b a c k ) ; } / / s o m e w h a t m i n d - b o g g l i n g t o g e t o u t o f : )
  3. PERHAPS... v a r i n c e p t

    i o n C a l l b a c k = f u n c t i o n ( e r r , d r e a m s ) { / / . . . d o e r r , o r d r e a m s i f s u c c e s s } ; a s y n c . s e r i e s ( [ f i r s t D r e a m , d r e a m S e c o n d D r e a m , d r e a m W i t h i n A D r e a m ] , i n c e p t i o n C a l l b a c k ) ;
  4. INTRO TO ASYNC.JS Utilities for flow control and more Uses

    err first (i.e.f u n c t i o n ( e r r , r e s u l t s ) ) callbacks - the node way Still popular github.com/caolan/async
  5. ASYNC.JS SERIES Run the functions in the tasks array in

    series, each one running after previous function has completed. If any tasks pass an error to its callback, the *final* callback is immediately called with the value of the error. Otherwise, *final* callback receives an array of results when tasks have completed. f u n c t i o n m o e s B e e r R e c i p e ( ) { a s y n c . s e r i e s ( [ f u n c t i o n p r e p a r e B r e w ( c a l l b a c k ) { v a r b r e w e d B e e r = b r e w B e e r ( ) ; / / r e t u r n s ' B r e w e d B e e r ' c a l l b a c k ( n u l l , b r e w e d B e e r ) ; } , f u n c t i o n a d d S e c r e t S a u c e ( c a l l b a c k ) { / / A d d s o m e s e c r e t s a u c e v a r s e c r e t S a u c e = ' C o u g h S y r u p ' ; c a l l b a c k ( n u l l , s e c r e t S a u c e ) ; } ] , f u n c t i o n ( e r r , r e s u l t s ) { / / r e s u l t s i s n o w e q u a l t o [ ' B r e w e d B e e r ' , ' C o u g h S y r u p ' ] } ) ; }
  6. ASYNC.JS PARALLEL Async.parallel allows you to execute tasks in parallel

    (Here the t a s k functions take an ( e r r , r e s u l t ) callback Once the tasks have completed, the results are passed to the final callback as an array. f u n c t i o n b r o w s e r S t a r t u p ( ) { a s y n c . p a r a l l e l ( [ f u n c t i o n c h e c k E m a i l ( c a l l b a c k ) { . . . } , f u n c t i o n g o o g l e S e a r c h ( c a l l b a c k ) { . . . } , f u n c t i o n p l a y Y o u t u b e ( c a l l b a c k ) { . . . } ] , c a l l b a c k ) } ;
  7. ASYNC.WATERFALL What if you want to chain together some tasks

    in series, and then work with all the result(s) at end? This is a waterfall: Each task starts when the last one completed successfully. If one calls callback(err), we call te finalCallback Similar to series right? (Hint: difference is where you get the result) Note: Agile (and Lean) is probably better a s y n c . w a t e r f a l l ( [ b u i l d A G r e a t B u s i n e s s P l a n ( c a l l b a c k ) , p i t c h T o B i g L e a g u e ( p l a n A , p l a n B , p l a n C , c a l l b a c k ) , w i s h Y o u r s e l f S o m e L u c k ( p l a n A B C , c a l l b a c k ) ] , f u n c t i o n f i n a l C a l l b a c k ( e r r ) { i f ( e r r ) { c o n s o l e . e r r o r ( e ) ; / / p r i n t o u t t h e e r r o r } e l s e { e x e c u t e P l a n ( p l a n A B C ) ; p r o c e s s . e x i t ( 1 ) ; / / e x i t y o u r s t a r t u p } } ) ;
  8. USING PROMISES INSTEAD A Promise represents a task (usually async)

    that can either succeed or fail. In Promise-land, we say that the task was either fulfilled* or rejected. a B e a u t i f u l P r o m i s e . t h e n ( f u n c t i o n ( ) { / * T h i s r u n s i f t h e P r o m i s e i s f u l f i l l e d . . . * / } , f u n c t i o n ( ) { / * . . . a n d t h i s r u n s i f t h e P r o m i s e i s r e j e c t e d * / } ) ;
  9. LETS LEARN TO USE PROMISES Instead of doing this… …you

    can do this: v a r m y L a m e C a l l b a c k = f u n c t i o n ( e r r , r e s u l t ) { i f ( e r r ) { / / . . t h r o w e r r o r l o g i t o r s o m e t h i n g } r e t u r n r e s u l t ; } ; s o m e F u n c t i o n W i t h A C a l l b a c k ( a r g 1 , m y L a m e C a l l b a c k ) ; m y G r e a t P r o m i s e = m y A w e s o m e F u n c t i o n ( ) ; m y G r e a t P r o m i s e . t h e n ( m y T r e m e n d o u s C a l l b a c k ) ; / / a d d c a l l b a c k s l a t e r m y G r e a t P r o m i s e . t h e n ( m y E v e n B e t t e r C a l l b a c k ) ; / / s t a c k ∞ c a l l b a c k s m y G r e a t P r o m i s e . t h e n ( n u l l , m y E r r o r H a n d l e r ) ; / / r e u s e e r r o r l o g i c
  10. WATERFALL (USING PROMISES) What if we want to iterate through

    an arbitrary array of Promise-returning task functions? (Was that functional or what?) f u n c t i o n p r o m i s e W a t e r f a l l ( t a s k s ) { f i n a l T a s k P r o m i s e = t a s k s . r e d u c e ( f u n c t i o n ( p r e v T a s k P r o m i s e , t a s k ) { r e t u r n p r e v T a s k P r o m i s e . t h e n ( t a s k ) ; } , r e s o l v e d P r o m i s e ) ; / / i n i t i a l v a l u e r e t u r n f i n a l T a s k P r o m i s e ; } / / r e : . r e d u c e T h e v a l u e r e t u r n e d b y r e d u c e w o u l d b e t h a t o f t h e l a s t c a l l b a c k i n v o c a t i o n
  11. PROMISES BASICALLY: A Promise that's neither fulfilled nor rejected is

    pending. A Promise's state can only change in two ways: pending → fulfilled pending → rejected In short, a Promise can only be fulfilled or rejected once.
  12. ASYNC.PARALLEL USING PROMISES Run an array of async tasks simultaneously,

    return a Promise that’s fulfilled with the results when all tasks have succeeded or rejected with an error when one has failed: Learn : A solid, fast Promises/A+ and when() implementation, plus other async goodies. jQuery calls it w h e n ( ) , calls it a l l ( ) . f u n c t i o n s e n d R e q u e s t s ( s o m e U R L S ) { v a r r e s u l t s = [ ] ; r e q u e s t P r o m i s e s = s o m e U R L S . m a p ( f u n c t i o n ( u r l ) { r e t u r n r e q u e s t ( { u r l : u r l } ) ; } ) ; r e t u r n w h e n . a l l ( r e q u e s t P r o m i s e s ) ; / / R e t u r n a p r o m i s e t h a t w i l l r e s o l v e o n l y o n c e a l l t } when.all when
  13. GIVE ME SOME PROMISE (LIBRARIES)! Awesome NodeJS list - Implementations-

    #control-flow github.com/promises-aplus/promises- spec/blob/master/implementations.md
  14. PROMISIFYALL BY BLUEBIRD Makes something callback-based into promises v a

    r P r o m i s e = r e q u i r e ( ' b l u e b i r d ' ) ; v a r f s = P r o m i s e . p r o m i s i f y A l l ( r e q u i r e ( ' f s ' ) ) ; / / t h e n f u r t h e r o n . . f s . r e a d F i l e A s y n c ( ' f i l e s / s o m e . j s o n ' ) . t h e n ( f u n c t i o n ( f i l e D a t a ) { r e t u r n f s . m k d i r A s y n c ( ' f i l e s / m , . , s o m e D i r e c t o r y ' ) ; } ) . t h e n ( f u n c t i o n ( ) { r e t u r n f s . w r i t e F i l e A s y n c ( ' s o m e D i r e c t o r y / s o m e . j s o n ' ) ; } )
  15. JQUERY.DEFERRED So changes made to .then() method. An exception thrown

    in a .then() callback now becomes a rejection value. Resolution state in a .then() is handled by its callback. Exceptions become rejection values and non-thenable returns become fulfillment values. *In jQuery, Promises are said to be resolved on success. But the Promises/A+ spec uses the word “resolved” to mean “either fulfilled or rejected,” and Promises/A+ is awesome. “ jQuery.Deferred objects are updated to be compatible with Promises/A+ and ES2015 Promises. Hence, there were ”
  16. JQUERY.DEFERRED EXAMPLE v a r p a r e n

    t = j Q u e r y . D e f e r r e d ( ) ; v a r c h i l d = p a r e n t . t h e n ( n u l l , f u n c t i o n ( ) { r e t u r n " b a r " ; } ) ; v a r c a l l b a c k = f u n c t i o n ( s t a t e ) { r e t u r n f u n c t i o n ( v a l u e ) { c o n s o l e . l o g ( s t a t e , v a l u e ) ; t h r o w n e w E r r o r ( " b a z " ) ; } ; } ; v a r g r a n d c h i l d r e n = [ c h i l d . t h e n ( c a l l b a c k ( " f u l f i l l e d " ) , c a l l b a c k ( " r e j e c t e d " ) ) , c h i l d . t h e n ( c a l l b a c k ( " f u l f i l l e d " ) , c a l l b a c k ( " r e j e c t e d " ) ) ] ; p a r e n t . r e j e c t ( " f o o " ) ; c o n s o l e . l o g ( " p a r e n t r e s o l v e d " ) ;
  17. ASYNC OR PROMISE!?? — , by @domenic “The thing is,

    promises are not about callback aggregation. That’s a simple utility. Promises are about something much deeper, namely providing a direct correspondence between synchronous functions and asynchronous functions.” You’re Missing the Point of Promises
  18. MORE INFO by @seilund , by @jcoglan Node.js async in

    practice: When to use what? Callbacks are Imperative, Promises are Functional