Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
RxJS
What’s RxJS ?
Lodash for async
Observable 

Library
Why we need RxJS ?
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(DOM) ...
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(DOM) ...
let isRequesting = false;
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM) > 0....
let isRequesting = false;
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM) > 0....
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM) > 0.9 #&& !isRequesting)
isReq...
Flag let isRequesting = false;
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM)...
let isRequesting = false;
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM) > 0....
let isRequesting = false;
scrollView.addEventListener('scroll', event !
const DOM = event.target;
if(hasScrolled(DOM) > 0....
const DOM = event.target;
if(hasScrolled(DOM) > 0.9 #&& !isRequesting)
isRequesting = true;
fetch('url%%...')
.then(res !=...
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(DOM) ...
What’s wrong ?
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(DOM) ...
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(DOM) ...
Flag
let isRequesting = false;
scrollView.addEventListener('scroll', event !=> {
const DOM = event.target;
if(hasScrolled(...
More Flags
let isRequesting = false;
let requestCount = 0;
const scrollHandler = function(event) {
const DOM = event.targe...
let isRequesting = false;
let requestCount = 0;
const scrollHandler = function(event) {
const DOM = event.target;
if(hasSc...
let isRequesting = false;
let requestCount = 0;
const scrollHandler = function(event) {
const DOM = event.target;
if(hasSc...
Jerry Hong
Front-End Engineer |
Website: blog.jerry-hong.com
Facebook: J.H.MingChen
ObservableObservable
What is Observable ?
What is Observable ?
Collection+ Time
Observable 

What is Observable ?
var mouseMove = Observable
.fromEvent(DOM, 'mousemove');
observable
var subscription = mouseMove
.subscribe(x !=> console....
Observable.of(2, 3, 4);
Observable.from([2, 3, 4]);
Observable.from(fetch('url'));
Observable.ajax('url');
Observable.from...
var sub = Observable
.from([1, 2, 3])
.map(x !=> x + 1)
.filter(x !=> x % 2 %%=== 0)
.subscribe({
next: x !=> console.log(...
observable
• Observable
•
• (subscribe)
• operators
var sub = Observable
.from([1, 2, 3])
.map(x !=> x + 1)
.filter(x !=> ...
operator
• Observable
•
•
observable ( )
var sub = Observable
.from([1, 2, 3])
.map(x !=> x + 1)
.filter(x !=> x % 2 %%===...
observer
• observable
• next 

error complete
.from([1, 2, 3])
.map(x !=> x + 1)
.filter(x !=> x % 2 %%=== 0)
.subscribe({...
subscription
• observable
•
(unsubscribe)
•
var sub = Observable
.from([1, 2, 3])
.map(x !=> x + 1)
.filter(x !=> x % 2 %%...
Marble Diagram
--a--b--c--d--e|
Marble Diagram
- (10 frames)
n(0-9/a-z) (next)
| (complete)
# (error)
()
time
----0---1---2---3--
----0---1---2---3|
----0...
Observable.of(1, 2, 3); (123|)
Observable.interval(10) --012-01-0-0123-01234-01234..
Observable
.fromEvent(DOM, 'click') ---e--ee-e--e-...
Observable.interval(10)
.take(3)
.map(x !=> x + 1)
.filter(x !=> x % 2 %%=== 1)
-01234..
-012|
-1-(3|)
-01(2|)
-12(3|)
Observable.interval(20) --0-1-2-3-4-5-6-7..
-------e-----------
--0-1-2|
.takeUntil(
Observable
.fromEvent(DOM, 'click')
);
Observable
.fromEvent(DOM, 'click')
.map(() !=>
ajax('url%%...'))
.mergeAll();
-----e-e----
-----o-o----
 
 ----r|
----r|
...
Observable
.fromEvent(DOM, 'click')
.mergeMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
--------...
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
-------...
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
Observable
.fromEvent(DOM, 'click')
.switchMap(() !=>
ajax('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
--!
----------...
Observable
.fromEvent(DOM, 'click')
.exhaustMap(() !=>
fetch('url%%...'))
-----e-e----
-----o-o----
 
 ----r|
----r|
-----...
Observable.fromEvent(scrollView, 'scroll')
.map(event !=> event.target)
.map(hasScrolled)
.filter(p !=> p > 0.9)
.exhaustM...
Make Your Code Clean
Readable
Readable Composable
Readable TestableComposable
Readable
Observable.fromEvent(scrollView, 'scroll')
.map(event !=> event.target)
.map(hasScrolled)
.filter(p !=> p > 0.9)
.exhaustM...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scroll$
.map(event !=> event.target)
.map(hasScrolled)
.filte...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scroll$
.map(event !=> event.target)
.map(hasScrolled)
.filte...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
const scrollOverNinetyPercent = Obs !=>
Obs.map(event !=> eve...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
const scrollOverNinetyPercent = Obs !=>
Obs.map(event !=> eve...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
const scrollOverNinetyPercent = Obs !=>
Obs.map(event !=> eve...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scrollOverNinetyPercent
scroll$
.let(scrollOverNinetyPercent)...
import { scrollOverNinetyPercent } from '%%...';
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scroll$
.let...
import { scrollOverNinetyPercent } from '%%...';
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scroll$
.let...
import { scrollOverNinetyPercent } from '%%...';
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
const getPos...
import { scrollOverNinetyPercent } from '%%...';
import { getPostObservable } from 'xxx';
const scroll$ = Observable
.from...
const scroll$ = Observable
.fromEvent(scrollView, 'scroll');
scroll$
.let(scrollOverNinetyPercent)
.exhaustMap(getPostObse...
Composable
const scrollOverNinetyPercent = Obs !=>
Obs.map(event !=> event.target)
.map(hasScrolled)
.filter(p !=> p > 0.9);
const scrollOver = criticalP !=> Obs !=>
Obs.map(event !=> event.target)
.map(hasScrolled)
.filter(p !=> p > criticalP);
H...
const scrollOver = criticalP !=>
pipe(
map(event !=> event.target),
map(hasScroll),
filter(p !=> p > criticalP)
);
lettabl...
import { scrollOverNinetyPercent } from '%%...';
import { getPostObservable } from 'xxx';
const scroll$ = Observable
.from...
import { scrollOver } from '%%...';
import { getPostObservable } from 'xxx';
const scroll$ = Observable
.fromEvent(scrollV...
pipe
operator
import { scrollOver } from '%%...';
import { getPostObservable } from 'xxx';
const scroll$ = Observable
.fro...
const getPostObservable = () !=>
Observable.ajax('url%%...');
retry 3
const getPostObservable = () !=>
Observable.ajax('url%%...')
.retry(3);
const defaultData = { success: false, data: [] };
const getPostObservable = () !=>
Observable.ajax('url%%...')
.retry(3)
....
Array
const defaultData = { success: false, data: [] };
const getPostObservable = () !=>
Observable.ajax('url%%...')
.retr...
lettable operator
import { retry, catchError } from 'rxjs/operators';
const defaultData = { success: false, data: [] };
co...
lettable operator
import { retry, catchError } from 'rxjs/operators';
const defaultData = { success: false, data: [] };
co...
import { retry, catchError } from 'rxjs/operators';
onErrorReturn
const defaultData = { success: false, data: [] };
const ...
Observable
Observable is composable
(Drag&Drop)
https://dribbble.com/shots/1074817-Drag-Drop-List-GIF
mouseDown$
mouseDown$
.switchMap(() !=> mouseMove$)
mouseDown$
mouseDown$
.switchMap(() !=> mouseMove$)
mouseDown$
.switchMap(() !=>
mouseMove$.takeUntil(mouseUp$))
mouseDown$
.switchMap(() !=>
mouseMove$.takeUntil(mouseUp$))
.subscribe(value !=> {
#// do something
});
mouseClick$
mouseClick$
.switchMap(() !=> request$)
mouseClick$
mouseClick$
.switchMap(() !=> request$)
mouseClick$
.switchMap(() !=>
request$.takeUntil(cancel$))
mouseClick$
.switchMap(() !=>
request$.takeUntil(cancel$))
.subscribe(value !=> {
#// do something
});
mouseClick$
.switchMap(() !=>
request$.takeUntil(cancel$))
.subscribe(value !=> {
#// do something
});
mouseClick$
.switchMap(() !=>
request$.takeUntil(cancel$))
.subscribe(value !=> {
#// do something
});
mouseDown$
.switchM...
Testable
Testing Asynchronous Code is
Hard
Testing Asynchronous Code is Hard
•
•
•
•
Testing Asynchronous Code is Hard
•
•
•
•
•
Marble Testing
Marble Testing
• Marble Diagram
•
• 100%
• RxJS
•
Observable.interval(10)
.take(3)
.map(x !=> x + 1)
.filter(x !=> x % 2 %%=== 1)
-01234..
-012|
-1-(3|)
-01(2|)
-12(3|)
it('interval', () !=> {
const actual = Observable.interval(10, testScheduler)
.take(3)
.map(x !=> x + 1)
.filter(x !=> x %...
https://youtu.be/i2A1S9o7ZFQ
Programming is thinking, not typing
– Cassey Pottan
Be a Programmer, not just a Coder
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
Prochain SlideShare
Chargement dans…5
×

RxJS - 封裝程式的藝術

5 060 vues

Publié le

這幾年來 JavaScript 有越來越多的語法糖(syntax sugar)像是 async/await, generator 等等,但我們實際上在處理非同步行為時,仍然要透過各種不同的方式;這使我們必須學習越來越多的語法,但程式碼卻更加難以閱讀。本次演講將會說明 RxJS 如何使用相同的方式處理各種非同步行為,以及我們要如何運用 Functional Programming 的觀念把複雜的非同步行為封裝成簡單可讀的程式碼。

Publié dans : Technologie
  • Visit this site: tinyurl.com/sexinarea and find sex in your area for one night)) You can find me on this site too)
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Sex in your area for one night is there tinyurl.com/hotsexinarea Copy and paste link in your browser to visit a site)
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Girls for sex are waiting for you https://bit.ly/2TQ8UAY
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Meetings for sex in your area are there: https://bit.ly/2TQ8UAY
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici

RxJS - 封裝程式的藝術

  1. 1. RxJS
  2. 2. What’s RxJS ?
  3. 3. Lodash for async
  4. 4. Observable Library
  5. 5. Why we need RxJS ?
  6. 6. 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; }); } });
  7. 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; }); } });
  8. 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;
  9. 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; });
  10. 10. 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
  11. 11. Flag let isRequesting = false; scrollView.addEventListener('scroll', event ! const DOM = event.target; if(hasScrolled(DOM) > 0.9 #&& !isRequesting) isRequesting = true; fetch('url%%...') .then(res !=> {
  12. 12. 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
  13. 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; }); } Request isRequest true
  14. 14. 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
  15. 15. 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; }); } });
  16. 16. What’s wrong ?
  17. 17. 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; }); } });
  18. 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; }); } }); 
 pattern
  19. 19. 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; }); } });
  20. 20. 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);
  21. 21. 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); 

  22. 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); 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
  23. 23. Jerry Hong Front-End Engineer | Website: blog.jerry-hong.com Facebook: J.H.MingChen
  24. 24. ObservableObservable
  25. 25. What is Observable ?
  26. 26. What is Observable ? Collection+ Time
  27. 27. Observable 
 What is Observable ?
  28. 28. var mouseMove = Observable .fromEvent(DOM, 'mousemove'); observable var subscription = mouseMove .subscribe(x !=> console.log(x)); subscription.unsubscribe();
  29. 29. 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
  30. 30. 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: () !=> {}, });
  31. 31. 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: () !=> {}, });
  32. 32. 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: () !=> {}, });
  33. 33. 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: () !=> {}, });
  34. 34. 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: () !=> {}, });
  35. 35. Marble Diagram --a--b--c--d--e|
  36. 36. 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|)
  37. 37. Observable.of(1, 2, 3); (123|)
  38. 38. Observable.interval(10) --012-01-0-0123-01234-01234..
  39. 39. Observable .fromEvent(DOM, 'click') ---e--ee-e--e-...
  40. 40. Observable.interval(10) .take(3) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 1) -01234.. -012| -1-(3|) -01(2|) -12(3|)
  41. 41. Observable.interval(20) --0-1-2-3-4-5-6-7.. -------e----------- --0-1-2| .takeUntil( Observable .fromEvent(DOM, 'click') );
  42. 42. Observable .fromEvent(DOM, 'click') .map(() !=> ajax('url%%...')) .mergeAll(); -----e-e---- -----o-o---- ----r| ----r| ---------r-r-
  43. 43. Observable .fromEvent(DOM, 'click') .mergeMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r| ---------r-r-
  44. 44. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r| -----------r-
  45. 45. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  46. 46. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  47. 47. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  48. 48. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  49. 49. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  50. 50. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  51. 51. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  52. 52. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  53. 53. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| ----r|
  54. 54. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --!
  55. 55. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --!
  56. 56. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --!
  57. 57. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --!
  58. 58. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --!
  59. 59. Observable .fromEvent(DOM, 'click') .switchMap(() !=> ajax('url%%...')) -----e-e---- -----o-o---- ----r| --! -----------r-
  60. 60. Observable .fromEvent(DOM, 'click') .exhaustMap(() !=> fetch('url%%...')) -----e-e---- -----o-o---- ----r| ----r| ---------r---
  61. 61. 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 });
  62. 62. Make Your Code Clean
  63. 63. Readable
  64. 64. Readable Composable
  65. 65. Readable TestableComposable
  66. 66. Readable
  67. 67. 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
  68. 68. 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
  69. 69. 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
  70. 70. 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
  71. 71. 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
  72. 72. 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
  73. 73. 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
  74. 74. import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view });
  75. 75. import { scrollOverNinetyPercent } from '%%...'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(() !=> fetch('url%%...')) .subscribe(res !=> { #// do something change view }); observable creator
  76. 76. 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 });
  77. 77. import { scrollOverNinetyPercent } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });
  78. 78. const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });
  79. 79. Composable
  80. 80. const scrollOverNinetyPercent = Obs !=> Obs.map(event !=> event.target) .map(hasScrolled) .filter(p !=> p > 0.9);
  81. 81. 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 > );
  82. 82. const scrollOver = criticalP !=> pipe( map(event !=> event.target), map(hasScroll), filter(p !=> p > criticalP) ); lettable operator import { map, filter } from 'rxjs/operators';
  83. 83. import { scrollOverNinetyPercent } from '%%...'; import { getPostObservable } from 'xxx'; const scroll$ = Observable .fromEvent(scrollView, 'scroll'); scroll$ .let(scrollOverNinetyPercent) .exhaustMap(getPostObservable) .subscribe(res !=> { #// do something change view });
  84. 84. 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 });
  85. 85. 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 });
  86. 86. const getPostObservable = () !=> Observable.ajax('url%%...');
  87. 87. retry 3 const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3);
  88. 88. const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3) .catch(() !=> Observable.of(defaultData));
  89. 89. Array const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .retry(3) .catch(() !=> [defaultData]);
  90. 90. lettable operator import { retry, catchError } from 'rxjs/operators'; const defaultData = { success: false, data: [] }; const getPostObservable = () !=> Observable.ajax('url%%...') .pipe( retry(3), catchError(() !=> [defaultData]) );
  91. 91. 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) );
  92. 92. 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 '%%...';
  93. 93. Observable
  94. 94. Observable is composable
  95. 95. (Drag&Drop) https://dribbble.com/shots/1074817-Drag-Drop-List-GIF
  96. 96. mouseDown$
  97. 97. mouseDown$ .switchMap(() !=> mouseMove$) mouseDown$
  98. 98. mouseDown$ .switchMap(() !=> mouseMove$)
  99. 99. mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$))
  100. 100. mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$)) .subscribe(value !=> { #// do something });
  101. 101. mouseClick$
  102. 102. mouseClick$ .switchMap(() !=> request$) mouseClick$
  103. 103. mouseClick$ .switchMap(() !=> request$)
  104. 104. mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$))
  105. 105. mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something });
  106. 106. mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something });
  107. 107. mouseClick$ .switchMap(() !=> request$.takeUntil(cancel$)) .subscribe(value !=> { #// do something }); mouseDown$ .switchMap(() !=> mouseMove$.takeUntil(mouseUp$)) .subscribe(value !=> { #// do something });
  108. 108. Testable
  109. 109. Testing Asynchronous Code is Hard
  110. 110. Testing Asynchronous Code is Hard • • • •
  111. 111. Testing Asynchronous Code is Hard • • • • •
  112. 112. Marble Testing
  113. 113. Marble Testing • Marble Diagram • • 100% • RxJS •
  114. 114. Observable.interval(10) .take(3) .map(x !=> x + 1) .filter(x !=> x % 2 %%=== 1) -01234.. -012| -1-(3|) -01(2|) -12(3|)
  115. 115. 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 }); });
  116. 116. https://youtu.be/i2A1S9o7ZFQ
  117. 117. Programming is thinking, not typing – Cassey Pottan
  118. 118. Be a Programmer, not just a Coder

×