RxJS - The Art of Abstraction

9b753d898d93aae8bd163db5c420a1ae?s=47 Jerry Hong
November 01, 2019

RxJS - The Art of Abstraction

9b753d898d93aae8bd163db5c420a1ae?s=128

Jerry Hong

November 01, 2019
Tweet

Transcript

  1. 2.

    Jerry Hong Tech Leader | Website: blog.jerry-hong.com Facebook: J.H.blog.tw Branch8

    2019 ModerWeb speaker 2018 FEDC organiser 2017 JSDC.tw speaker 2017 RxJS 30天鐵⼈人賽冠軍 2016 JSDC.tw speaker
  2. 7.

    let isRequesting = false; scrollView.addEventListener('scroll', event => { const DOM

    = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } });
  3. 8.

    let isRequesting = false; scrollView.addEventListener('scroll', event => { const DOM

    = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); 無限滾動 Infinite scroll
  4. 9.

    let isRequesting = false; scrollView.addEventListener('scroll', event = const DOM =

    event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; 註冊滾動事件 Listen scroll event
  5. 10.

    let isRequesting = false; scrollView.addEventListener('scroll', event = const DOM =

    event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); 判斷滾動⾼高度 Determine scroll height
  6. 11.

    scrollView.addEventListener('scroll', event = const DOM = event.target; if(hasScrolled(DOM) > 0.9

    && !isRequesting) isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); 發送 Request
  7. 12.

    設定 Flag let isRequesting = false; scrollView.addEventListener('scroll', event = const

    DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting = true; fetch('url...') .then(res => {
  8. 13.

    let isRequesting = false; scrollView.addEventListener('scroll', event = const DOM =

    event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); 若若 isRequesting 為 false 
 再發送 Request
  9. 14.

    let isRequesting = false; scrollView.addEventListener('scroll', event = const DOM =

    event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } 發送 Request 前, 設定 isRequest 為 true
  10. 15.

    const DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) isRequesting

    = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); Response 後, 設定 isRequest 為 false
  11. 16.

    let isRequesting = false; scrollView.addEventListener('scroll', event => { const DOM

    = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); 無限滾動 Infinite scroll
  12. 18.

    let isRequesting = false; scrollView.addEventListener('scroll', event => { const DOM

    = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); 兩兩個非同步⾏行行為
  13. 19.

    let isRequesting = false; scrollView.addEventListener('scroll', event => { const DOM

    = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } }); 同樣是非同步⾏行行為
 卻⽤用不同的 pattern
  14. 20.

    Flag let isRequesting = false; scrollView.addEventListener('scroll', event => { const

    DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; }); } });
  15. 21.

    More Flags let isRequesting = false; let requestCount = 0;

    const scrollHandler = function(event) { const DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; requestCount = requestCount + 1; if (requestCount === 3) { scrollView.removeEventListener('scroll', scrollHandler) } }) } } scrollView.addEventListener('scroll', scrollHandler);
  16. 22.

    let isRequesting = false; let requestCount = 0; const scrollHandler

    = function(event) { const DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; requestCount = requestCount + 1; if (requestCount === 3) { scrollView.removeEventListener('scroll', scrollHandler) } }) } } scrollView.addEventListener('scroll', scrollHandler); 我們⼀一定要寫
 這麼醜的程式碼嗎?
  17. 23.

    let isRequesting = false; let requestCount = 0; const scrollHandler

    = function(event) { const DOM = event.target; if(hasScrolled(DOM) > 0.9 && !isRequesting) { isRequesting = true; fetch('url...') .then(res => { // do something change view isRequesting = false; requestCount = requestCount + 1; if (requestCount === 3) { scrollView.removeEventListener('scroll', scrollHandler) } }) } } scrollView.addEventListener('scroll', scrollHandler); fromEvent(scrollView, 'scroll') .pipe( map(event "=> event.target), map(hasScrolled), filter(p "=> p > 0.9), exhaustMap(() "=> ajax('url""...')), take(3) ) .subscribe(res "=> { "// do something change view }) VanillaJS RxJS
  18. 28.

    var mouseMove = fromEvent(DOM, 'mousemove'); observable 建立與訂閱 var subscription =

    mouseMove .subscribe(x => console.log(x)); subscription.unsubscribe();
  19. 30.

    import { from } from 'rxjs'; import { map, filter

    } from 'rxjs/operators'; var sub = from([1, 2, 3]) .pipe( map(x "=> x + 1), filter(x "=> x % 2 ""=== 0) ); .subscribe({ next: x "=> console.log(x), error: err "=> {}, complete: () "=> {}, });
  20. 31.

    observable • Observable 的物件實例例 • 在未被訂閱之前,只是 個物件,不會有任何 Side Effect •

    可被訂閱(subscribe) import { from } from 'rxjs'; import { map, filter } from 'rxjs/operators var sub = from([1, 2, 3]) .pipe( map(x "=> x + 1), filter(x "=> x % 2 ""=== 0) ); .subscribe({ next: x "=> console.log(x), error: err "=> {},
  21. 32.

    operator • ⼀一個 function 傳入 observable 回傳 observable • 可對元素作運算處理理

    import { from } from 'rxjs'; import { map, filter } from 'rxjs/operators var sub = from([1, 2, 3]) .pipe( map(x "=> x + 1), filter(x "=> x % 2 ""=== 0) ); .subscribe({ next: x "=> console.log(x), error: err "=> {}, complete: () "=> {}, });
  22. 33.

    observer • ⼀一個 object • 具有 next, error, complete •

    ⽤用來來訂閱 observable map(x "=> x + 1), filter(x "=> x % 2 ""=== 0) ); .subscribe({ next: x "=> console.log(x), error: err "=> {}, complete: () "=> {}, });
  23. 34.

    subscription • observable 訂閱後回傳 的物件 • 可拿來來退訂 (unsubscribe) • 可以其他

    subscription 合併 import { from } from 'rxjs'; import { map, filter } from 'rxjs/operators var sub = from([1, 2, 3]) .pipe( map(x "=> x + 1), filter(x "=> x % 2 ""=== 0) ); .subscribe({ next: x "=> console.log(x), error: err "=> {}, complete: () "=> {}, });
  24. 35.
  25. 37.

    Marble Diagram - ⼀一⼩小段時間 (10 frames) n(0-9/a-z) 送出的元素(next) | 送出結束

    (complete) # 送出錯誤 (error) () 同步送出 time ----0---1---2---3-- ----0---1---2---3| ----0---1---2---3--# (123|)
  26. 41.

    interval(10) .pipe( take(3), map(x "=> x + 1), filter(x "=>

    x % 2 ""=== 1) ) -01234.. -012| -1-(3|) -01(2|) -12(3|)
  27. 62.

    fromEvent(scrollView, 'scroll') .pipe( map(event "=> event.target), map(hasScrolled), filter(p "=> p

    > 0.9), exhaustMap(() "=> ajax('url""...')), take(3) ) .subscribe(res "=> { "// do something change view })
  28. 65.
  29. 67.

    Make a HTTP request Listen an events
 
 Read a

    file A set of values A set of values A set of values
  30. 68.

    A set of values A set of values A set

    of values Observable Make a HTTP request Listen an events
 
 Read a file
  31. 76.
  32. 83.

    mouseClick$.pipe( switchMap(() "=> request$.pipe(takeUntil(cancel$)) ); ); .subscribe((value) "=> { "//

    do something }) mouseDown$.pipe( switchMap(() "=> mouseMove$.pipe(takeUntil(mouseUp$)) ) ) .subscribe(value "=> { "// do something }); 取消請求 Cancel Request 拖拉 D&D
  33. 88.
  34. 90.

    const postUser$ = r.pipe( r.matchPath('/user'), r.matchType('POST'), r.useEffect(req$ "=> req$.pipe( map(req

    "=> req.body as User), mergeMap(Dao.postUser), map(response "=> ({ body: response })) )));
  35. 93.
  36. 94.

    const pingEpic = action$ "=> action$.pipe( filter(action "=> action.type ""===

    'PING'), delay(1000), "// Asynchronously wait 1000ms then continue mapTo({ type: 'PONG' }) );
  37. 95.
  38. 98.