You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RxJS is a library for composing asynchronous and event-based programs by using observable sequences.
It provides:
one core type, the Observable,
satellite types (Observer, Schedulers, Subjects)
operators to allow handling asynchronous events as collections
The essential concepts in RxJS which solve async event management are:
Observable: represents the idea of an invokable collection of future values or events.
Observer: is a collection of callbacks that knows how to listen to values delivered by the Observable.
Subscription: represents the execution of an Observable, is primarily useful for cancelling the execution.
Operators: are pure functions that enable a functional programming style of dealing with collections with operations like map, filter, concat, reduce, etc.
Subject: is the equivalent to an EventEmitter, and the only way of multicasting a value or event to multiple Observers.
Schedulers: are centralized dispatchers to control concurrency, allowing us to coordinate when computation happens on e.g. setTimeout or requestAnimationFrame or others.
You need to:
subscribe the "observable"
with "observer" definiton of what you are going to do when something happened
then you must unsubscribe the "subscription"
optionally you can define pipeline with "operators" for "observable"
Marble Diagrams
Marble Diagrams are visual representations of how operators work, and include the input Observable(s), the operator and its parameters, and the output Observable.
Observables
Executing Observables
There are three types of values an Observable Execution can deliver:
"Next" notification: sends a value such as a Number, a String, an Object, etc.
"Error" notification: sends a JavaScript Error or exception.
Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables.
Whenever any input Observable emits a value, it computes a formula using the latest values from all the inputs, then emits the output of that formula.
if you pass n Observables to operator, returned Observable will always emit an array of n values, in order corresponding to order of passed Observables
even if some Observable completes, result of combineLatest will still emit values when other Observables do.
if any Observable errors, combineLatest will error immediately as well, and all other Observables will be unsubscribed
constfirstTimer=timer(0,1000);// emit 0, 1, 2... after every second, starting from nowconstsecondTimer=timer(500,1000);// emit 0, 1, 2... after every second, starting 0,5s from nowconstcombinedTimers=combineLatest(firstTimer,secondTimer);// Logs// [0, 0] after 0.5s// [1, 0] after 1s// [1, 1] after 1.5s// [2, 1] after 2s
Creating with "concat()"
Creates an output Observable which sequentially emits all values from given Observable and then moves on to the next.
Concatenates multiple Observables together by sequentially emitting their values, one Observable after the other
if some input Observable never completes, concat will also never complete and Observables following the one that did not complete will never be subscribed.
If any Observable in chain errors, instead of passing control to the next Observable, concat will error immediately as well.
Wait for Observables to complete and then combine last values they emitted.
Accepts:
an Array of ObservableInput or
a dictionary Object of ObservableInput
Returns an Observable that emits either:
an array of values in the exact same order as the passed array, or
a dictionary of values in the same shape as the passed dictionary.
constobservable=forkJoin({foo: of(1,2,3,4),bar: Promise.resolve(8),baz: timer(4000)});// Logs:// { foo: 4, bar: 8, baz: 0 } after 4 secondsconstobservable=forkJoin([of(1,2,3,4),Promise.resolve(8),timer(4000)]);// Logs:// [4, 8, 0] after 4 seconds
Creating with "merge()"
Flattens multiple Observables together by blending their values into one Observable.
Creates an output Observable which concurrently emits all values from every given input Observable
constclicks=fromEvent(document,"click");consttimer=interval(1000);constclicksOrTimer=merge(clicks,timer);// Results in the following:// timer will emit ascending values, one every second(1000ms) to console// clicks logs MouseEvents to console everytime the "document" is clicked
Creating with "race()"
Returns an Observable that mirrors the first source Observable to emit an item.
are the kind that can be piped to Observables using the syntax observableInstance.pipe(operator())
When called, they do not change the existing Observable instance, they return a new Observable.
A Pipeable Operator is essentially a pure function which takes one Observable as input and generates another Observable as output.
Subscribing to the output Observable will also subscribe to the input Observable.
Creation Operators:
are the other kind of operator, which can be called as standalone functions to create a new Observable.
Creating Custom Operator
You must
implement all three Observer functions, next(), error(), and complete() when subscribing to the input Observable.
implement a "teardown" function that cleans up when the Observable completes (in this case by unsubscribing and clearing any pending timeouts).
return that teardown function from the function passed to the Observable constructor.
import{Observable}from"rxjs";functiondelay(delayInMillis){returnobservable=>newObservable(observer=>{// this function will called each time this// Observable is subscribed to.constallTimerIDs=newSet();constsubscription=observable.subscribe({next(value){consttimerID=setTimeout(()=>{observer.next(value);allTimerIDs.delete(timerID);},delayInMillis);allTimerIDs.add(timerID);},error(err){observer.error(err);},complete(){observer.complete();}});// the return value is the teardown function,// which will be invoked when the new// Observable is unsubscribed from.return()=>{subscription.unsubscribe();allTimerIDs.forEach(timerID=>{clearTimeout(timerID);});};});}
Transformation Operators
buffer
Buffers the source Observable values until closingNotifier emits.
Collects values from the past as an array, and emits that array only when another Observable emits.
constclicks=fromEvent(document,"click");constintervalEvents=interval(1000);constbuffered=intervalEvents.pipe(buffer(clicks));// interval counter will be buffered and printed out when document clicked// after clicked new buffer will be started
bufferCount
Buffers the source Observable values until the size hits the maximum bufferSize given
constclicks=fromEvent(document,"click");constbuffered=clicks.pipe(bufferCount(2));// Emit the last two click events as an array
bufferTime
Buffers the source Observable values for a specific time period.
Groups the items emitted by an Observable according to a specified criterion, and emits these grouped items as GroupedObservables, one GroupedObservable per group.
Emits the given constant value on the output Observable every time the source Observable emits a value.
fromEvent(document,"click").pipe(mapTo("Hi"));
concatMap
Maps each value to an Observable, then flattens all of these inner Observables using concatAll.
concatMap does not subscribe to the next observable until the previous completes
constclicks=fromEvent(document,"click");constresult=clicks.pipe(concatMap(ev=>interval(1000).pipe(take(4))));// (results are not concurrent)// For every click on the "document" it will emit values 0 to 3 spaced// on a 1000ms interval// click -> 1000ms-> 0 -1000ms-> 1 -1000ms-> 2 -1000ms-> 3
concatMapTo
Projects each source value to the same Observable which is merged multiple times in a serialized fashion on the output Observable
constclicks=fromEvent(document,"click");constresult=clicks.pipe(concatMapTo(interval(1000).pipe(take(4))));// (results are not concurrent)// For every click on the "document" it will emit values 0 to 3 spaced// on a 1000ms interval// click -> 1000ms-> 0 -1000ms-> 1 -1000ms-> 2 -1000ms-> 3
exhaust
Flattens an Observable-of-Observables by dropping the next inner Observables while the current inner is still executing.
exhaust ignores every new inner Observable if the previous Observable has not yet completed.
On each emission the previous inner observable is cancelled and the new observable is subscribed.
You can remember this by the phrase switch to a new observable.
This works perfectly for scenarios like typeaheads where you are no longer concerned with the response of the previous request when a new input arrives.
This also is a safe option in situations where a long lived inner observable could cause memory leaks
fromEvent(document,"click").pipe(switchMap(()=>interval(1000))// restart counter on every click);
A Subscription has one important method, unsubscribe, that takes no argument and just disposes the resource held by the subscription
Unsubscribing (Disposing)
Because Observable Executions may be infinite, and it's common for an Observer to want to abort execution in finite time, we need an API for canceling an execution.
Since each execution is exclusive to one Observer only, once the Observer is done receiving values, it has to have a way to stop the execution, in order to avoid wasting computation power or memory resources.