Slide 1

Slide 1 text

RxJS ੗蕕纷ୗጱ萬蔩

Slide 2

Slide 2 text

What’s RxJS ?

Slide 3

Slide 3 text

Lodash for async

Slide 4

Slide 4 text

Ӟ㮆蝚螂 Observable 奲ݳݱ圵覍ݶྍᤈ傶ጱ Library

Slide 5

Slide 5 text

Why we need RxJS ?

Slide 6

Slide 6 text

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; }); } });

Slide 7

Slide 7 text

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; }); } }); 篷褖笔㵕

Slide 8

Slide 8 text

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; 戢㲘笔㵕Ԫկ

Slide 9

Slide 9 text

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; }); ڣ䥁笔㵕ṛଶ

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

戔ਧ Flag let isRequesting = false; scrollView.addEventListener('scroll', event ! const DOM = event.target; if(hasScrolled(DOM) > 0.9 #&& !isRequesting) isRequesting = true; fetch('url%%...') .then(res !=> {

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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; }); } }); 篷褖笔㵕

Slide 16

Slide 16 text

What’s wrong ?

Slide 17

Slide 17 text

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; }); } }); 獋㮆覍ݶྍᤈ傶

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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; }); } });

Slide 20

Slide 20 text

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);

Slide 21

Slide 21 text

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); ౯㮉Ӟਧᥝ䌃
 蝡讕蠨ጱ纷ୗ嘨㻟牫

Slide 22

Slide 22 text

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); Observable.fromEvent(scrollView, 'scroll') .map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9) .exhaustMap(() !=> fetch('url%%...')) .take(3) .subscribe(res !=> { #// do something change view }); VanillaJS RxJS

Slide 23

Slide 23 text

Jerry Hong Front-End Engineer | Website: blog.jerry-hong.com Facebook: J.H.MingChen

Slide 24

Slide 24 text

Observable 墋Օ Observable 墋Օ

Slide 25

Slide 25 text

What is Observable ?

Slide 26

Slide 26 text

What is Observable ? Collection + Time

Slide 27

Slide 27 text

Observable 疰猟ฎӞ㮆ଧڜ牧
 愊ᶎጱزᔰ䨝褰茐碻樌വ蝑 What is Observable ?

Slide 28

Slide 28 text

var mouseMove = Observable .fromEvent(DOM, 'mousemove'); observable ୌ缏膏懪褂 var subscription = mouseMove .subscribe(x !=> console.log(x)); subscription.unsubscribe();

Slide 29

Slide 29 text

Observable.of(2, 3, 4); Observable.from([2, 3, 4]); Observable.from(fetch('url')); Observable.ajax('url'); Observable.fromEvent(DOM, 'click'); Observable.interval(1000); ୌ缏 observable

Slide 30

Slide 30 text

var sub = Observable .from([1, 2, 3]) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 0) .subscribe({ next: x !=> console.log(x), error: err !=> {}, complete: () !=> {}, });

Slide 31

Slide 31 text

observable • Observable ጱᇔկ䋿ֺ • ࣁ๚ᤩ懪褂ԏ獮牧ݝฎ 㮆ᇔկ牧犋䨝蝑ڊزᔰ • ݢᤩ懪褂(subscribe) • ٍ磪ग़圵 operators var sub = Observable .from([1, 2, 3]) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 0) .subscribe({ next: x !=> console.log(x), error: err !=> {}, complete: () !=> {}, });

Slide 32

Slide 32 text

operator • Observable ጱොဩ • ݢ䌘زᔰ֢螀ᓒ蒂ቘ • ࿞螐ࢧ㯽Ӟ㮆碝ጱ observable (磪ֺक़) var sub = Observable .from([1, 2, 3]) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 0) .subscribe({ next: x !=> console.log(x), error: err !=> {}, complete: () !=> {}, });

Slide 33

Slide 33 text

observer • አ㬵懪褂 observable ጱ ᇔկ • next 獢ୗӞਧᥝ磪牧
 error 膏 complete ݢ螡 䢔 .from([1, 2, 3]) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 0) .subscribe({ next: x !=> console.log(x), error: err !=> {}, complete: () !=> {}, });

Slide 34

Slide 34 text

subscription • observable 懪褂盅ࢧ㯽 ጱᇔկ • ݢ೭㬵蝐懪 (unsubscribe) • ݢ犥ٌ犢懪㻌ݳ㬫 var sub = Observable .from([1, 2, 3]) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 0) .subscribe({ next: x !=> console.log(x), error: err !=> {}, complete: () !=> {}, });

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Marble Diagram --a--b--c--d--e|

Slide 37

Slide 37 text

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|)

Slide 38

Slide 38 text

Observable.of(1, 2, 3); (123|)

Slide 39

Slide 39 text

Observable.interval(10) - -012 -01 -0 -0123 -01234 -01234..

Slide 40

Slide 40 text

Observable .fromEvent(DOM, 'click') ---e--ee-e--e-...

Slide 41

Slide 41 text

Observable.interval(10) .take(3) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 1) -01234.. -012| -1-(3|) -01(2|) -12(3|)

Slide 42

Slide 42 text

Observable.interval(20) --0-1-2-3-4-5-6-7.. -------e----------- --0-1-2| .takeUntil( Observable .fromEvent(DOM, 'click') );

Slide 43

Slide 43 text

Observable .fromEvent(DOM, 'click') .map(() !=> ajax('url%%...')) .mergeAll(); -----e-e---- -----o-o---- \ \ \ ----r| ----r| ---------r-r-

Slide 44

Slide 44 text

Observable .fromEvent(DOM, 'click') .mergeMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r| ---------r-r-

Slide 45

Slide 45 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r| -----------r-

Slide 46

Slide 46 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 47

Slide 47 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 48

Slide 48 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 49

Slide 49 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 50

Slide 50 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 51

Slide 51 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 52

Slide 52 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 53

Slide 53 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 54

Slide 54 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r|

Slide 55

Slide 55 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --!

Slide 56

Slide 56 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --!

Slide 57

Slide 57 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --!

Slide 58

Slide 58 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --!

Slide 59

Slide 59 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --!

Slide 60

Slide 60 text

Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| --! -----------r-

Slide 61

Slide 61 text

Observable .fromEvent(DOM, 'click') .exhaustMap(() !=> fetch('url%%...')) -----e-e---- -----o-o---- \ \ \ ----r| ----r| ---------r---

Slide 62

Slide 62 text

Observable.fromEvent(scrollView, 'scroll') .map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9) .exhaustMap(() !=> fetch('url%%...')) .take(3) .subscribe(res !=> { #// do something change view });

Slide 63

Slide 63 text

Make Your Code Clean

Slide 64

Slide 64 text

Readable

Slide 65

Slide 65 text

Readable Composable

Slide 66

Slide 66 text

Readable Testable Composable

Slide 67

Slide 67 text

Readable

Slide 68

Slide 68 text

Observable.fromEvent(scrollView, 'scroll') .map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); ು玲磪఺嬝ጱ
 Observable

Slide 69

Slide 69 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); Assign 妔虋碍

Slide 70

Slide 70 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); ು玲ڊ
 蝢አጱ Operator

Slide 71

Slide 71 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9); scrollOverNinetyPercent(scroll$) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); Naming Function

Slide 72

Slide 72 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); 硬አ let operator

Slide 73

Slide 73 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); 硬አ let operator

Slide 74

Slide 74 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scrollOverNinetyPercent scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); const scroll$ = Observable .fromEvent(scrollView, 'scroll'); const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); 硬አ let operator

Slide 75

Slide 75 text

import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); 硯ک加缏ጱ䲆礯

Slide 76

Slide 76 text

import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); ು櫝 observable creator

Slide 77

Slide 77 text

import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); const getPostObservable = () !=> fetch('url%%...');
 scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view }); 狕硬ܻ๜ጱ纷ୗ嘨 import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); getPostObservable
 scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });

Slide 78

Slide 78 text

import { scrollOverNinetyPercent } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view }); 硯ک加缏ጱ䲆礯

Slide 79

Slide 79 text

const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });

Slide 80

Slide 80 text

Composable

Slide 81

Slide 81 text

const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9); 犋অ᯿奲

Slide 82

Slide 82 text

const scrollOver = criticalP !=> Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > criticalP); Higher Order Function const scrollOver = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > );

Slide 83

Slide 83 text

const scrollOver = criticalP !=> pipe( map(event !=> event.target), map(hasScroll), filter(p !=> p > criticalP) ); 硬አ lettable operator import { map, filter } from 'rxjs/operators';

Slide 84

Slide 84 text

ܻ๜ጱ纷ୗ嘨 import { scrollOverNinetyPercent } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });

Slide 85

Slide 85 text

狕硬盅 import { scrollOver } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOver(0.9)) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });

Slide 86

Slide 86 text

硬አ pipe 奲ݳ operator import { scrollOver } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .pipe( scrollOver(0.9), exhaustMap(getPostObservable) ) .subscribe(res !=> { #// do something change view }); import { scrollOver } from '%%...'; import { getPostObservable } from 'xxx'; import { exhaustMap } from 'rxjs/operators'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .pipe( scrollOver(0.9), exhaustMap(getPostObservable) ) .subscribe(res !=> { #// do something change view });

Slide 87

Slide 87 text

玲஑෈ᒍ const getPostObservable = () !=> Observable.ajax('url%%...');

Slide 88

Slide 88 text

०硻盅 retry 3 稞 const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3);

Slide 89

Slide 89 text

ইຎ᯿手ӣ稞Ֆ०硻牧 ࢧ㯽毆戔独 const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3) .catch(() !=> Observable.of(defaultData));

Slide 90

Slide 90 text

ࢧ㯽 Array const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3) .catch(() !=> [defaultData]);

Slide 91

Slide 91 text

硬አ lettable operator import { retry, catchError } from 'rxjs/operators'; const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .pipe( retry(3), catchError(() !=> [defaultData]) );

Slide 92

Slide 92 text

ୌ缏ᛔ૩ጱ lettable operator import { retry, catchError } from 'rxjs/operators'; const defaultData = { success: false, data: [] }; const onErrorReturn = defaultData !=> catchError(() !=> [defaultData]); const getPostObservable = () !=> Observable.ajax('url%%...') .pipe( retry(3), onErrorReturn(defaultData) );

Slide 93

Slide 93 text

硯ک加缏ጱ䲆礯 import { retry, catchError } from 'rxjs/operators'; onErrorReturn const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .pipe( retry(3), onErrorReturn(defaultData) ); import { onErrorReturn } from '%%...';

Slide 94

Slide 94 text

哴ݢ胼ֵአ Observable

Slide 95

Slide 95 text

Observable is composable

Slide 96

Slide 96 text

ᇔկ瞫೉ (Drag&Drop) https://dribbble.com/shots/1074817-Drag-Drop-List-GIF

Slide 97

Slide 97 text

mouseDown$

Slide 98

Slide 98 text

mouseDown$ .switchMap(() !=> mouseMove$) mouseDown$

Slide 99

Slide 99 text

mouseDown$ .switchMap(() !=> mouseMove$)

Slide 100

Slide 100 text

mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$))

Slide 101

Slide 101 text

mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$)) .subscribe(value !=> { #// do something });

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

mouseClick$

Slide 104

Slide 104 text

mouseClick$ .switchMap(() !=> request$) mouseClick$

Slide 105

Slide 105 text

mouseClick$ .switchMap(() !=> request$)

Slide 106

Slide 106 text

mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$))

Slide 107

Slide 107 text

mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something });

Slide 108

Slide 108 text

mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something });

Slide 109

Slide 109 text

mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something }); mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$)) .subscribe(value !=> { #// do something }); 玲窞藶穩 瞫೉

Slide 110

Slide 110 text

Testable

Slide 111

Slide 111 text

Testing Asynchronous Code is Hard

Slide 112

Slide 112 text

Testing Asynchronous Code is Hard • 秇硈覍ݶྍ介手 • 眐ह蕦褾犋অ秇硈牧Ӭ਻ฃڊ梊 • ڊ梊碻犋Ꭳ螇ᥝತ抑 • 羊嘦覍ݶྍ介手

Slide 113

Slide 113 text

No content

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

Testing Asynchronous Code is Hard • 秇硈覍ݶྍ介手 • 眐ह蕦褾犋অ秇硈牧Ӭ਻ฃڊ梊 • ڊ梊碻犋Ꭳ螇ᥝತ抑 • 羊嘦覍ݶྍ介手 • 介手䨝臺揲螂ग़ጱ碻樌

Slide 117

Slide 117 text

Marble Testing

Slide 118

Slide 118 text

Marble Testing • አ Marble Diagram 砰䌃介手 • ݝᥝ䨝向瑽疰胼䌃介手 • 100% ݢ᯿蕦ጱ介手 • RxJS ൉׀碻樌秇硈 • 犋襑ᥝ臺碻樌缛盃介手奾ຎ

Slide 119

Slide 119 text

Observable.interval(10) .take(3) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 1) -01234.. -012| -1-(3|) -01(2|) -12(3|)

Slide 120

Slide 120 text

it('interval', () !=> { const actual = Observable.interval(10, testScheduler) .take(3) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 1); testScheduler.expectObservable(actual) .toBe('-a-(b|)', { a: 1, b: 3 }); });

Slide 121

Slide 121 text

https://youtu.be/i2A1S9o7ZFQ

Slide 122

Slide 122 text

Programming is thinking, not typing – Cassey Pottan

Slide 123

Slide 123 text

Be a Programmer, not just a Coder