RxJS In-Depth - AngularConnect 2015
-
Upload
ben-lesh -
Category
Technology
-
view
2.236 -
download
3
Transcript of RxJS In-Depth - AngularConnect 2015
RxJS and Angular
RxJS In-Depth(Formerly a talk called Reactive Streams in Angular 1 and 2)
We had a last-minute pivot on talk content, because Jeff Cross and Rob Wormald wanted to ruin my week last week.
Ben LeshSenior UI EngineerEdge Developer Experience
RxJS Nexthttp://github.com/ReactiveX/RxJS
RxJS Next is now RxJS 5.0.0-alpha
RxJS 5 is community drivenSpear-headed by contributors at Netflix, Google and Microsoft. With many other contributors under the ReactiveX community banner.
RxJS 5 GoalsPerformanceImproved debuggingES7 observable spec alignment
PerformanceDecisions were guided by performance testingTried out 4-5 different architectures in the beginning> 120 micro performance tests~ 10 macro performance tests around common scenarios and bottlenecks
RxJS 5 operators are4.3x faster on average
Call-stack depth and debugging was a common complaint in older versions of RxJS
RxJS 4
RxJS 5
Thanks in huge part to contributions from
Paul TaylorOJ KwonAndr StaltzJeff Cross
Luis GabrielAdrian OmeloJinrohRob Wormwald
really every one of our contributors.https://github.com/ReactiveX/RxJS/graphs/contributors
Thanks to guidance from
Matt PodwysockiJafar HusainErik MeijerBen ChristensenGeorge CampbellAaron Tull
were closing in on beta in the next month or so
What is RxJS?Reactive programmingTreating events as collectionsManipulating sets of events with operators
RxJS is LoDash or Underscore for async.
Angular 2 is usingRxJS 5 Observables for async
Angular has traditionally used Promises for async
PromisesRead-only view to a single future valueSuccess and error semantics via .then()Not lazy. By the time you have a promise, its on its way to being resolved.Immutable and uncancellable. Your promise will resolve or reject, and only once.
ObservableStreams or setsOf any number of thingsOver any amount of timeLazy. Observables will not generate values via an underlying producer until theyre subscribed to.Can be unsubscribed from. This means the underlying producer can be told to stop and even tear down.
Both Promises and Observablesare built to solve problems around async(to avoid callback hell)
Types of async in modern web applicationsDOM events AnimationsAJAXWebSocketsSSEAlternative inputs (voice, joystick, etc)
Promises only really make sense for one of theseDOM events (0-N values)Animations (cancelable)AJAX (1 value)WebSockets (0-N values)SSE (0-N values)Alternative inputs (0-N values)
except when they dontSingle page applications commonly prepare data via AJAX for each view shownWhen the view changes, the next view probably doesnt care about the previous views dataFortunately, XHRs can be aborted!but promise-based AJAX implementations cannot be aborted, because promises cannot be cancelled.*
So how do we go from Promises to Observables?
They have some similar semanticsthen x.(valueFn, errorFn);subscribe
They have some similar semanticsx.subscribe(valueFn, errorFn);, completeFn
Observable also has cancellation semantics!let sub = x.subscribe(valueFn, errorFn, completeFn);
// ...some time latersub.unsubscribe();
Creating Observables is similar to creating Promises
creating a Promiselet p = new Promise((resolve, reject) => { doAsyncThing((err, value) => { if (err) { reject(err); } else { resolve(value); } });});
creating an Observablelet o = new Observable(observer => { doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } });});
if the producers resource allows cancellation, we can handle that herelet o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } });
});const token return () => { cancelAsyncThing(token); };
when you call o.subscribe()let o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } });
return () => { cancelAsyncThing(token); };}); observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } });
return () => {
};});
when you call subscription.unsubscribe()let o = new Observable(observer => { const token = doAsyncThing((err, value) => { if (err) { observer.error(err); } else { observer.next(value); observer.complete(); } });
return () => { cancelAsyncThing(token); };});
return () => { cancelAsyncThing(token); };
Dont worry... youre unlikely to be creating your own Observables
Observable creation helpers in RxJSObservable.of(value, value2, value3, )Observable.from(promise/iterable/observable)Observable.fromEvent(item, eventName)Angulars HTTP and Realtime Data servicesMany community-driven RxJS modules and libraries
Error Handling in Observables is also similar to Promise
catchmyPromise.catch(error => { if (error instanceof OkayError) { return Promise.resolve(okay); } else { throw error; }});
catchmyObservable.catch(error => { if (error instanceof OkayError) { return Observable.of(okay); } else { throw error; }});
finally(some promise impls)myPromise.finally(() => { console.log(done);});
finallymyObservable.finally(() => { console.log(done);});
Observables can be retriedmyObservable.retry(3);
myObservable.retryWhen(errors => errors.delay(3000));
Quick Recap on ObservableAn observable is a set of any number of things over any amount of time.
Quick Recap on ObservableAll values are pushed to the nextHandler
observable.subscribe(nextHandler);
Quick Recap on ObservableThe errorHandler is called if the producer experiences an error
observable.subscribe(nextHandler, errorHandler);
Quick Recap on ObservableThe completionHandler is called when the producer completes successfully
observable.subscribe(nextHandler, errorHandler, completionHandler);
Quick Recap on ObservableObservables are lazy. It doesnt start producing data until subscribe() is called.
observable.subscribe(nextHandler, errorHandler, completionHandler);
Quick Recap on Observablesubscribe() returns a subscription, on which a consumer can call unsubscribe() to cancel the subscription and tear down the producer
let sub = observable.subscribe(nextHandler, errorHandler, completionHandler);sub.unsubscribe();
What are operators?Theyre methods on Observable that allow you to compose new observables.
How operators worklet result = source.myOperator();
result is an Observable, that when subscribed to, subscribes to source, then tranforms its values in some way and emits them.
How operators worksubscription.unsubscribe();
when unsubscribe() is called on that subscription, the unsubscription logic from both result and source are called.
How operators workOperators pass each value from one operator to the next, before proceeding to the next value in the set.*This is different from array operators (think map and filter) which will process the entire array at each step.*This can be changed with Schedulers.
Array filter, map, reduce
Observable filter, map, reduce
simple operatorsmap()filter()reduce()first()last()single()elementAt()toArray()isEmpty()take()skip()startWith()and many more
merging and joining operatorsmergemergeMap (flatMap)concatconcatMapswitchswitchMapcombineLatestwithLatestFromzipforkJoinexpand
splitting and grouping operatorsgroupBywindowpartition
buffering strategy operatorsbufferthrottledebouncesample
With ES7 function bind, you can roll your own*(*coming soon to TypeScript?)
hot vs cold observablesObservables are cold by defaultCold observables create a new producer each time a consumer subscribes to themHot observables share a single producer with every consumer that subscribes to them.
Multiplexed WebSocketConnect to a web socket serverFor each data streamsend a subscription message to the serverfilter out responses from the serverwhen done, send an unsubscription message.Ideally, the socket is only open while you require data from it.
Multiplexed WebSocketRECONNECTION?!maintain a state of all of the multiplexed data streams your views need.check to see when youre able to reconnectreconnect the socketonce the socket is reopened, send all of the subscription messages again
Create an Observable that wraps a WebSocket
It will create the WebSocketwhen you subscribe()
It emits messages eventsthat arrive on the WebSocket
And when it unsubscribes,it will tear down the WebSocket!
Share to make it hotWe dont want each subscriptioncreating its own websocket.
Create an Observable that wraps ourSocket Observable
filter the messagesfrom the Socket Observableto what you needand subscribe
Send a message tothe server to start gettingthe data over the socket
on unsubscribe, tell the server to stop sending dataand unsubscribe from the socket observable
Add a retryWhen to retry the whole thingif something goes wrong with the multiplexed observable
share the observable to make it hot, so many consumers can share this producer.
Example Time!
Never trust anyone with only good things to say about their library/framework.
Whats bad in RxJS?Zalgo.. dont use mutable outer scoped variables in your operators or subscriptions!Unbounded buffers! The zip operator in particular is dangerous here.Too many operators to remember.
Twitter: @benleshgithub: [email protected]: Comments.BETTER: Questions.BEST: Corrections!Thank you!