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

Better Callbacks with Deferred Object

Better Callbacks with Deferred Object

An introduction on why and how to use a deferred object in JavaScript. Presented by Patrick Berkeley to the Burlington Web Application Group.

Avatar for Patrick Berkeley

Patrick Berkeley

December 07, 2012
Tweet

Other Decks in Programming

Transcript

  1. It all starts with an innocent little ajax request: v

    a r d a t a ; $ . g e t ( ' a p i / d a t a ' , f u n c t i o n ( r e s p ) { d a t a = r e s p . d a t a ; } ) ; d o S o m e t h i n g F a n c y W i t h D a t a ( d a t a ) ;
  2. ASYCHRONICITY Sequencing is hard and leads to: Continuation Passing Style

    (CPS). Deep nesting. 'Callback hell'. Parallelizing is even harder.
  3. SEQUENCING / / D e m o n s t

    r a t e s n e s t i n g , C P S , ' c a l l b a c k h e l l ' / / $ . g e t ( ' a p i 1 / d a t a ' , f u n c t i o n ( r e s p 1 ) { / / N e x t t h a t d e p e n d e d o n t h e f i r s t r e s p o n s e . $ . g e t ( ' a p i 2 / d a t a ' , f u n c t i o n ( r e s p 2 ) { / / N e x t r e q u e s t t h a t d e p e n d e d o n t h e s e c o n d r e s p o n s e . $ . g e t ( ' a p i 3 / d a t a ' , f u n c t i o n ( r e s p 3 ) { / / N e x t r e q u e s t t h a t d e p e n d e d o n t h e t h i r d r e s p o n s e . $ . g e t ( ) ; / / . . . y o u g e t t h e i d e a . } ) ; } ) ; } ) ;
  4. PARALLELIZING $ . g e t ( ' a p

    i 1 / d a t a ' , f u n c t i o n ( r e s p 1 ) { t r a c k M e ( ) ; } ) ; $ . g e t ( ' a p i 2 / d a t a ' , f u n c t i o n ( r e s p 2 ) { t r a c k M e ( ) ; } ) ; $ . g e t ( ' a p i 3 / d a t a ' , f u n c t i o n ( r e s p 3 ) { t r a c k M e ( ) ; } ) ; v a r t r a c k e d C o u n t = 0 ; f u n c t i o n t r a c k M e ( ) { + + t r a c k e d C o u n t ; i f ( t r a c k e d C o u n t = = = 3 ) { d o S o m e t h i n g T h a t N e e d e d A l l T h r e e ( ) ; } }
  5. THE PLAYERS / / T h e d e f

    e r r e d o b j e c t i t s e l f . v a r d e f = $ . D e f e r r e d ; / / A n d t h e d e f e r r e d ' s p r o m i s e o b j e c t . d e f . p r o m i s e ( ) ;
  6. $.DEFERRED() d e f ; > { a l w

    a y s : f u n c t i o n ( ) { } , d o n e : f u n c t i o n ( ) { } , f a i l : f u n c t i o n ( ) { } , n o t i f y : f u n c t i o n ( ) { } , n o t i f y W i t h : f u n c t i o n ( ) { } , p i p e : f u n c t i o n ( ) { } , p r o g r e s s : f u n c t i o n ( ) { } , p r o m i s e : f u n c t i o n ( ) { } , r e j e c t : f u n c t i o n ( ) { } , r e j e c t W i t h : f u n c t i o n ( ) { } , r e s o l v e : f u n c t i o n ( ) { } , r e s o l v e W i t h : f u n c t i o n ( ) { } , s t a t e : f u n c t i o n ( ) { } , t h e n : f u n c t i o n ( ) { } }
  7. PROMISE() / / A r e a d - o

    n l y v e r s i o n o f t h e d e f e r r e d o b j e c t ; / / r e t u r n e d f r o m a j Q u e r y $ . a j a x ( ) c a l l . d e f . p r o m i s e ( ) ; > { a l w a y s : f u n c t i o n ( ) { } , d o n e : f u n c t i o n ( ) { } , f a i l : f u n c t i o n ( ) { } , p i p e : f u n c t i o n ( ) { } , p r o g r e s s : f u n c t i o n ( ) { } , p r o m i s e : f u n c t i o n ( ) { } , s t a t e : f u n c t i o n ( ) { } , t h e n : f u n c t i o n ( ) { } }
  8. RESOLVE() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . p r o m i s e ( ) . s t a t e ( ) ; > " p e n d i n g " d e f e r r e d . r e s o l v e ( ) ; d e f e r r e d . p r o m i s e ( ) . s t a t e ( ) ; > " r e s o l v e d "
  9. REJECT() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . p r o m i s e ( ) . s t a t e ( ) ; > " p e n d i n g " d e f e r r e d . r e j e c t ( ) ; d e f e r r e d . p r o m i s e ( ) . s t a t e ( ) ; > " r e j e c t e d "
  10. PIPE() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . p i p e ( f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I f i l t e r d o n e r e s p o n s e s " , r e s p ) ; } , f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I f i l t e r f a i l r e s p o n s e s " , r e s p ) ; } , f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I f i l t e r p r o g r e s s r e s p o n s e s " , r e s p ) ; } ) ;
  11. DONE() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . r e s o l v e ( ) ; d e f e r r e d . d o n e ( f u n c t i o n ( ) { c o n s o l e . l o g ( " I g e t c a l l e d w h e n t h i n g s g o w e l l . " ) ; } ) ;
  12. FAIL() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . r e j e c t ( ) ; d e f e r r e d . f a i l ( f u n c t i o n ( ) { c o n s o l e . l o g ( " I g e t c a l l e d w h e n t h i n g s f a l l a p a r t . " ) ; } ) ;
  13. ALWAYS() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; d e f e r r e d . r e s o l v e ( ) ; d e f e r r e d . a l w a y s ( f u n c t i o n ( ) { c o n s o l e . l o g ( " I ' m s o p o p u l a r , I g e t c a l l e d n o m a t t e r w h a t . " ) ; } ) ;
  14. THEN() v a r d e f e r r

    e d = $ . D e f e r r e d ( ) ; / / S h o r t h a n d f o r d o n e , f a i l , a n d a l w a y s . d e f e r r e d . t h e n ( f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I ' m a d o n e c a l l b a c k ! " , r e s p ) ; } , f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I ' m a f a i l c a l l b a c k . " , r e s p ) ; } , f u n c t i o n ( r e s p ) { c o n s o l e . l o g ( " I ' m a n a l w a y s c a l l b a c k . " , r e s p ) ; } ) ;
  15. SEQUENCING MESS $ . g e t ( ' a

    p i 1 / d a t a ' , f u n c t i o n ( r e s p 1 ) { / / N e x t t h a t d e p e n d e d o n t h e f i r s t r e s p o n s e . $ . g e t ( ' a p i 2 / d a t a ' , f u n c t i o n ( r e s p 2 ) { / / N e x t r e q u e s t t h a t d e p e n d e d o n t h e s e c o n d r e s p o n s e . $ . g e t ( ' a p i 3 / d a t a ' , f u n c t i o n ( r e s p 3 ) { / / N e x t r e q u e s t t h a t d e p e n d e d o n t h e t h i r d r e s p o n s e . } ) ; } ) ; } ) ;
  16. DEFERRED SEQUENCING v a r r e q 1 =

    $ . g e t ( ' a p i 1 / d a t a ' ) ; v a r r e q 2 = $ . g e t ( ' a p i 2 / d a t a ' ) ; v a r r e q 3 = $ . g e t ( ' a p i 3 / d a t a ' ) ; r e q 1 . t h e n ( f u n c t i o n ( r e q 1 D a t a ) { r e t u r n r e q 2 ; } ) . t h e n ( f u n c t i o n ( r e q 2 D a t a ) { r e t u r n r e q 3 ; } ) ; r e q 2 . t h e n ( f u n c t i o n ( r e q 2 D a t a ) { / / D o s o m e t h i n g s o m e w h e r e e n t i r e l y d i f f e r e n t . } ) ;
  17. UGLY PARALLEL REQUESTS $ . g e t ( '

    a p i 1 / d a t a ' , f u n c t i o n ( r e s p 1 ) { t r a c k M e ( ) ; } ) ; $ . g e t ( ' a p i 2 / d a t a ' , f u n c t i o n ( r e s p 2 ) { t r a c k M e ( ) ; } ) ; $ . g e t ( ' a p i 3 / d a t a ' , f u n c t i o n ( r e s p 3 ) { t r a c k M e ( ) ; } ) ; v a r t r a c k e d C o u n t = 0 ; f u n c t i o n t r a c k M e ( ) { + + t r a c k e d C o u n t ; i f ( t r a c k e d C o u n t = = = 3 ) { d o S o m e t h i n g T h a t N e e d e d A l l T h r e e ( ) ; } }
  18. DEFERRED PARALLELIZATION $ . w h e n ( $

    . g e t ( ' a p i 1 / d a t a ' ) , $ . g e t ( ' a p i 2 / d a t a ' ) , $ . g e t ( ' a p i 3 / d a t a ' ) , { k e y : ' v a l u e ' } ) . d o n e ( ) ;
  19. FILTERED RESPONSES v a r g e t A r

    t i c l e B y H e a d l i n e = f u n c t i o n ( q u e r y ) { r e t u r n $ . a j a x ( { u r l : ' a p i / a r t i c l e s ' } ) . p i p e ( f u n c t i o n ( d a t a ) { / / F i l t e r a r t i c l e h e a d l i n e s b y q u e r y . } ) ; } g e t A r t i c l e B y H e a d l i n e ( ' w i n s e l e c t i o n ' ) . d o n e ( f u n c t i o n ( a r t i c l e s ) { / / D o w i t h t h e a r t i c l e s . } ) ;
  20. SUMMARY Really good when you need to guarantee something else

    has completed before proceeding, either one after another or all together. Improves code composition: flat decoupled
  21. RESOURCES Callbacks, promises, and coroutines Q.js from jQuery Creating Responsive

    Applications Using jQuery Deferred and Promises ASYNCH JS: THE POWER OF $.DEFERRED jQuery : Exploring Deferred and Promise methods