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

From Imperative To Reactive Thinking

From Imperative To Reactive Thinking

Todd Motto

July 10, 2017
Tweet

More Decks by Todd Motto

Other Decks in Programming

Transcript

  1. DISCOVERING PATTERNS Ob se rve r Pa tte rn Se

    que nce s a nd O pe ra tors
  2. PATTERNS DISCOVERED Ob se rve r Pa tte rn Se

    que nce s a nd O pe ra tors
  3. Elements of our game 1. <div id="james">James</div> 2. <div id="todd">Todd</div>

    3. <div id="ball"></div> 4. 5. <button id="start">Start</button>
  4. Game Helpers 6. const CHANCE_OF_BAD_THROW = 0.5; 7. 8. //

    Throw affects chances of catching 9. function checkDropped(isBadThrow): boolean; 1. // Helpers to move ball around in the game 2. function addBall(player: Element): void; 3. function removeBall(player: Element): void; 4. 5. // Simple 50/50 chance of bad throw We use the throw quality to determine whether the ball is caught or not.
  5. TODO 1. S ta rt the ga me on `

    sta rtB tn` click 2. Th row a nd ca tch the ball be twee n 2 pla ye rs 3. Check each th row to see if i t wa s “bad” 4. Check ca tch, e ndi ng the ga me on d rop
  6. Starting the game 1. function handleClick() { 2. // our

    game code 3. } 4. 5. startBtn.addEventListener('click', handleClick);
  7. TODO 1. S ta rt the ga me on `

    sta rtB tn` click 2. Th row a nd ca tch the ball be twee n 2 pla ye rs 3. Check each th row to see if i t wa s “bad” 4. Check ca tch, e ndi ng the ga me on d rop
  8. 5. // TODO 6. // - person1 starts with ball

    7. // - wait while they get ready to throw 1. // Our two refs to the people DOM nodes 2. throwAndCatchBetween(james, todd); 3. 4. function throwAndCatchBetween(person1, person2) {
  9. Core throwing and catching 2. // person1 starts with ball

    1. function throwAndCatchBetween(person1, person2) {
  10. ...now for humans 1. function throwAndCatchBetween(person1, person2) { 2. //

    person1 starts with ball 3. addBall(person1); 4. 5. // wait while they get ready to throw 6. setTimeout(() => { 7. 8. // person1 throws ball 9. removeBall(person1); 10. 11. // ball travels through the air 12. setTimeout(() => { 13. 14. // person2 catches ball 15. addBall(person2); 16. 17. // Back again! 18. throwAndCatchBetween(person2, person1); 19. Ball flies throught the air for 1 second before being caught.
  11. TODO 1. S ta rt the ga me on `

    sta rtB tn` click 2. Th row a nd ca tch the ball be twee n 2 pla ye rs 3. Check each th row to see if i t wa s “bad” 4. Check ca tch, e ndi ng the ga me on d rop
  12. Check throw quality 8. // person1 throws ball 9. removeBall(person1);

    10. // capture if throw was bad 11. const isBadThrow = 12. Math.random() <= CHANCE_OF_BAD_THROW; 1. function throwAndCatchBetween(person1, person2) { 2. // person1 starts with ball 3. addBall(person1); 4. 5. // wait while they get ready to throw 6. setTimeout(() => { 7. 13. 14. // ball travels through the air 15. setTimeout(() => { 16. 17. // person2 catches ball 18. addBall(person2); 19. 20. // Back again! 21. throwAndCatchBetween(person2, person1);
  13. TODO 1. S ta rt the ga me on `

    sta rtB tn` click 2. Th row a nd ca tch the ball be twee n 2 pla ye rs 3. Check each th row to see if i t wa s “bad” 4. Check ca tch, e ndi ng the ga me on d rop
  14. Check if ball was dropped 10. // capture if throw

    was bad 11. const isBadThrow = 12. Math.random() <= CHANCE_OF_BAD_THROW; 13. 14. // ball travels through the air 15. setTimeout(() => { 16. 17. if (checkDropped(isBadThrow)) { 18. return // Game over: Ball dropped 19. } 3. addBall(person1); 4. 5. // wait while they get ready to throw 6. setTimeout(() => { 7. 8. // person1 throws ball 9. removeBall(person1); 20. 21. // person2 catches ball 22. addBall(person2); 23. 24. // Back again! 25. throwAndCatchBetween(person2, person1); 26.
  15. 1. S ta rt the ga me on ` sta

    rtB tn` click 2. Th row a nd ca tch the ball be twee n 2 pla ye rs 3. Check each th row to see if i t wa s “bad” 4. Check ca tch, e ndi ng the ga me on d rop
  16. TODO 1. Ob se rvable<S ta rt b utton click

    s> 2. Ob se rvable<Th rowi ng the ball> 3. Ob se rvable<Ca tchi ng ( or not!) the ball>
  17. Observable<Start button clicks> 6. // Start listening for clicks 7.

    game$.subscribe(); 1. const startClick$ = Rx.Observable 2. .fromEvent(startBtn, 'click'); 3. 4. const game$ = startClick$; 5. We subscribe to the Observable to begin actually listening for the start button click events.
  18. Turn a click into throw and catch! 4. const game$

    = startClick$ 5. .switchMap( 6. handleThrowAndCatchBetween(james, todd) 7. ); 1. const startClick$ = Rx.Observable 2. .fromEvent(startBtn, 'click'); 3. 8. 9. // Start listening for clicks 10. game$.subscribe();
  19. Core throwing and catching 1. // Usage 2. .switchMap( 3.

    handleThrowAndCatchBetween(james, todd) 4. ); 5.
  20. TODO 1. Ob se rvable<S ta rt b utton click

    s> 2. Ob se rvable<Pe rson th rowi ng the ball> 3. Ob se rvable<Pe rson ca tchi ng the ball>
  21. What events make up a "throw"? 1. // person1 starts

    with ball 2. addBall(person1); 3. 4. // wait while they get ready to throw 5. setTimeout(() => { 6. 7. // person1 throws ball 8. // capture if throw was bad 9. removeBall(person1); 10. const isBadThrow = 11. Math.random() <= CHANCE_OF_BAD_THROW; 12. We can extract the relevant concepts from our imperative example...
  22. Observable<Person throwing the ball> 1. // capture if throw was

    bad 2. const isBadThrow = 3. Math.random() <= CHANCE_OF_BAD_THROW; 4. 5. const throw$ = Rx.Observable.of(isBadThrow); We can make our initial throw$ stream encapsulate the throw quality (so we can evaluate it later).
  23. Observable<Person throwing the ball> 9. // ball travels through the

    air 10. .delay(1000); 1. // capture if throw was bad 2. const throw$ = Rx.Observable.of(isBadThrow) 3. // person1 starts with ball 4. .do(() => addBall(person1)) 5. // wait while they get ready to throw 6. .delay(1000) 7. // person1 throws ball 8. .do(() => removeBall(person1))
  24. Observable<Person throwing the ball> 4. return Rx.Observable.of(isBadThrow) 5. .do(() =>

    addBall(person)) 6. .delay(1000) 7. .do(() => removeBall(person)) 8. .delay(1000); 9. } 1. function handleThrow$From(person) { 2. const isBadThrow = 3. Math.random() <= CHANCE_OF_BAD_THROW;
  25. "Plug in" the throwing for p1 and p2 1. //

    Usage 2. .switchMap( 3. handleThrowAndCatchBetween(james, todd) 4. ); 5.
  26. TODO 1. Ob se rvable<S ta rt b utton click

    s> 2. Ob se rvable<Pe rson th rowi ng the ball> 3. Ob se rvable<Pe rson ca tchi ng the ball>
  27. What events make up a "catch"? 5. // Ball is

    caught succesfully 6. return Rx.Observable.of('') 7. .do(() => addBall(person)) 1. // Ball is dropped 2. if (checkDropped(isBadThrow)) { 3. return Rx.Observable.throw(`Ball dropped`) 4. } If the ball is caught, we return an Observable (the value isn't important) and add the ball to the person as normal.
  28. Observable<Person catching the ball> 2. // The returned function will

    be used within 1. function handleCatch$By(person) { The `isBadThrow` value will be passed in via the switchMap from the previous throw$
  29. "Plug in" the throwing for p1 and p2 1. //

    Usage 2. .switchMap( 3. handleThrowAndCatchBetween(james, todd) 4. ); 5.
  30. 1. Ob se rvable<S ta rt b utton click s>

    2. Ob se rvable<Pe rson th rowi ng the ball> 3. Ob se rvable<Pe rson ca tchi ng the ball>