Upload
tdc-globalcode
View
102
Download
3
Embed Size (px)
Citation preview
Globalcode – Open4education
Node.js – Reactive Programming with Observables and RxJS
Felipe Rohde
Globalcode – Open4education
Agenda
Application goalsAsync JSPromises vs. Observables
Data model - StreamsBasic usageObservablesCreation from scratchQuick recap
RxJS to the rescueWhat is thisCreation helpersOperators“hot" vs. “cold" Use case - Resilient web socket
Globalcode – Open4education
Application goals
Keep responsive all the times - React on loadUnacceptable halt while processingResilient - React on fail - Self recoverReactiveImpossible to predict when process will be doneAdvantage of Async
Globalcode – Open4education
Async JS
Levels of async computationsTime and latency become key issuesSimple applications “callback" is enoughBut to scale … hard to maintain, hard to testAsync computation is hard to manage
Globalcode – Open4education
Callback Hell
makeHttpCall('/items', items => { for (itemId of items) { makeHttpCall(`/items/${itemId}/info`, itemInfo => { makeHttpCall(`/items/${itemInfo.pic}`, img => { showImg(img); }); }); }});
Globalcode – Open4education
Async JS
Callbacks (Callback Hell)Promises (ES6 Spec)GeneratorsAsync / AwaitObservables (ES7 Spec)
Globalcode – Open4education
Promises vs. Observables
Both are built to solve async problems (to avoid callback hell)The idea of future valuesEventual resultsCode scalability
Globalcode – Open4education
Promises vs. Observables
Fluent interface with notion of time and exposes the method continuallyRead-only view to a single future valueSuccess and fail semantics via .then() and .catch()Not lazy, once started, it is on the way to being resolvedNot cancellable, it will resolve or reject, only once
Globalcode – Open4education
Promises vs. Observables
makeHttpCall('/items') .then(itemId => makeHttpCall(`/items/${itemId}/info`)) .then(itemInfo => makeHttpCall(`/items/${itemInfo}.pic}`)) .then(showImg);
Globalcode – Open4education
Promises vs. Observables
“Streams” or collectionsAny amount of dataAny amount of timeLazy, by default. Just produce values when there are subscribersCan be cancelled, stop producing valuesObjects that can inform other objects of the changes they publish
Globalcode – Open4education
Promises vs. Observables
Single return value Multiple return values
Pull / Sync / Interactive Object Iterables (Array, Set, Map, Object)
Push / Async / Reactive Promise Observable
“Observables, returns 0 - ∞ values between now and the end of time”
Globalcode – Open4education
Data Model - Streams
Nothing more than a sequence of events/data over timeStreams are immutable, data can just be changed with another streamVariables with the ability to react to changes emitted from the data to a certain point
Globalcode – Open4education
Data Model - Streams
“With observables, anything is a streamand, it is good”
Array Stream
MSFT [$44, $45, $46, $45] {$44.. $45…. $4…. $45}
NFLX [$95, $96, $97, $96, $101] {$95. $96…$97…. $96…}
Globalcode – Open4education
Observables
The most important conceptWrap a piece of data and decorate it with stream-like qualities (string, numbers, sets, collections, websocket, requests, …any)The most simple is Observable.of(anything)
Globalcode – Open4education
Basic Usage
Promise Observable
.then(valueFn) .subscribe(valueFn, errorFn, completeFn)
.catch(err => Promise.resolve(err)) .catch(err => Observable.of(err))
.finally(() => console.log(‘done’)) .finally(() => console.log(‘done’))
Not cancellable let sub = observable.subscribe(valueFn)sub.unsubscribe();
Globalcode – Open4education
Creation from scratch
Promise Observable
new Promise((resolve, reject) => { asyncFn((err, data) => { if (err) { return reject(err); }
resolve(data); });});
new Observable(subscriber => { asyncFn((err, data) => { if (err) { return subscriber.error(err); }
subscriber.next(data); subscriber.complete(); });
return () => cancelAnything();});
Globalcode – Open4education
Quick recap
Set of any amount of things over any amount of time.Values are pushed, to subscribers, via nextFn.Errors are pushed to errFn.On complete completeFn is called.By default, they are lazy, nothing is produced until at least one subscriber.
let sub = observable.subscribe(nextFn, errFn, completeFn)sub.unsubscribe()
Globalcode – Open4education
RxJS to the rescue
Globalcode – Open4education
What is this?
“RxJS is lodash for async” with ObservablesFunctional / reactive Programming with ObservablesHandle events, or any source, as stream collectionsMany, many, many operators to manipulate setsDecisions guided by performanceContributors at Netflix, Google and Microsoft
Globalcode – Open4education
Creation helpers
Observable.of(…values);Observable.from(typeof promise / iterable)Observable.fromEvent(item, eventName)Observable.fromPromise(PromiseLike)Observable.fromCallback((callback) => ..);Observable.fromNodeCallback((err, callback) => ..);Observable.interval(number);range(number, number);Observable…
Globalcode – Open4education
Can be retried / repeated
// retry three times on failObservable.retry(3);
// retry always on failObservable.retry();
// retry after 1,5s on failObservable.retryWhen(errors => errors.delay(1500));
// always repeat on completeObservable.repeat();
// repeat twiceObservable.repeat(2);
Globalcode – Open4education
Can be combined / connected// combine values whenever any emitObservable.combineLatest(…Observables);
// emits all when all completesObservable.forkJoin(…Observables);
// emit chunks when all at same index have emittedObservable.zip(…Observables);
// parallel combinationObservable.merge(…Observables);
// serial combinationObservable.concat(…Observables);
// connect streams with merge strategyObservable.mergeMap(() => Observable);
Globalcode – Open4education
Operators - The real power
Globalcode – Open4education
Operators - What is this
Methods to compose Observables and create new ones.
let mapped = Observable.interval(1000) .filter(value => value % 2) .map(value => value * 3) .take(3);
Mapped is a new Observable that when subscribed, subscribes to interval observable and theirs operators.
Globalcode – Open4education
Operators - How they work
Operators pass each value from one to the next, before process next set’s value, like lazy evaluation.Different from array operators, which process whole array, creating intermediates for each step.
Globalcode – Open4education
Arrays way
Items.filter(notRed).map(toScale).take(3);
Globalcode – Open4education
Operators way
Items.filter(notRed).map(toScale).take(3);
Globalcode – Open4education
Some operators
Basicmap, reduce, filter, first, last, toArray, take, skip, scan, repeat, max, min,
expand, forEach, do, pluck, …
Merging and joiningmerge, concat, mergeMap, concatMap,
switchMap, forkJoin, race, combineLatest, zip, …
Splitting and grouping groupBy, window, partition, pairwise, withLatestFrom, …
Buffer and backpressure Buffer, throttle, debounce, sample, distinctUntilChanged, …
Fail tolerance and redundancy strategies catch, retry, retryWhen, onErrorResumeNext, publishReplay, …
Globalcode – Open4education
Hot vs. Cold
Observables are “cold” by defaultCold observables create a new producer each time a subscriber subscribes to them.Hot observables share a single producer with every subscriber. And optionally can emit values without any subscriber (Like mouse events).
Globalcode – Open4education
Use Case - Resilient Websocket
Connect to a web socket serverFor each subscriber
Send subscription to serverFilter desired responsesWhen done, unsubscribe
Ideally, keep socket opened just while data is required
Globalcode – Open4education
Use Case - Resilient Websocket
On connection failKeep state of all subscribersCheck when able to reconnectReconnectOnce reconnected, send subscriptions againKeep consuming
Globalcode – Open4education
Use Case - Resilient Websocket
http://tdc-rxjs.herokuapp.comhttps://github.com/feliperohdee/tdc-rxjs-demo
Globalcode – Open4education
Use case - Websocket Observable
Globalcode – Open4education
Use case - Resilient web socket
Globalcode – Open4education
Felipe Rohde
[email protected]/feliperohdee
github.com/feliperohdeehttps://www.npmjs.com/package/one-framework