Learn Rxjs
Learn Rxjs
of Contents
Learn RxJS
Introduction 1.1
Operators 1.2
Combination 1.2.1
combineAll 1.2.1.1
combineLatest 1.2.1.2
concat 1.2.1.3
concatAll 1.2.1.4
forkJoin 1.2.1.5
merge 1.2.1.6
mergeAll 1.2.1.7
pairwise 1.2.1.8
race 1.2.1.9
startWith 1.2.1.10
withLatestFrom 1.2.1.11
zip 1.2.1.12
Conditional 1.2.2
defaultIfEmpty 1.2.2.1
every 1.2.2.2
iif 1.2.2.3
sequenceequal 1.2.2.4
Creation 1.2.3
create 1.2.3.1
empty 1.2.3.2
from 1.2.3.3
fromEvent 1.2.3.4
1
interval 1.2.3.5
of 1.2.3.6
range 1.2.3.7
throw 1.2.3.8
timer 1.2.3.9
Error Handling 1.2.4
catch / catchError 1.2.4.1
retry 1.2.4.2
retryWhen 1.2.4.3
Multicasting 1.2.5
publish 1.2.5.1
multicast 1.2.5.2
share 1.2.5.3
shareReplay 1.2.5.4
Filtering 1.2.6
audit 1.2.6.1
auditTime 1.2.6.2
debounce 1.2.6.3
debounceTime 1.2.6.4
distinctUntilChanged 1.2.6.5
filter 1.2.6.6
first 1.2.6.7
ignoreElements 1.2.6.8
last 1.2.6.9
sample 1.2.6.10
single 1.2.6.11
skip 1.2.6.12
skipUntil 1.2.6.13
skipWhile 1.2.6.14
take 1.2.6.15
2
takeUntil 1.2.6.16
takeWhile 1.2.6.17
throttle 1.2.6.18
throttleTime 1.2.6.19
Transformation 1.2.7
buffer 1.2.7.1
bufferCount 1.2.7.2
bufferTime 1.2.7.3
bufferToggle 1.2.7.4
bufferWhen 1.2.7.5
concatMap 1.2.7.6
concatMapTo 1.2.7.7
exhaustMap 1.2.7.8
expand 1.2.7.9
groupBy 1.2.7.10
map 1.2.7.11
mapTo 1.2.7.12
mergeMap / flatMap 1.2.7.13
partition 1.2.7.14
pluck 1.2.7.15
reduce 1.2.7.16
scan 1.2.7.17
switchMap 1.2.7.18
toArray 1.2.7.19
window 1.2.7.20
windowCount 1.2.7.21
windowTime 1.2.7.22
windowToggle 1.2.7.23
windowWhen 1.2.7.24
Utility 1.2.8
3
do / tap 1.2.8.1
delay 1.2.8.2
delayWhen 1.2.8.3
dematerialize 1.2.8.4
finalize / finally 1.2.8.5
let 1.2.8.6
repeat 1.2.8.7
timeout 1.2.8.8
toPromise 1.2.8.9
Full Listing 1.2.9
Subjects 1.3
AsyncSubject 1.3.1
BehaviorSubject 1.3.2
ReplaySubject 1.3.3
Subject 1.3.4
Recipes 1.4
Game Loop 1.4.1
Horizontal Scroll Indicator 1.4.2
Http Polling 1.4.3
Progress Bar 1.4.4
Smart Counter 1.4.5
Type Ahead 1.4.6
Concepts 1.5
RxJS v5 -> v6 Upgrade 1.5.1
Understanding Operator Imports 1.5.2
4
Introduction
Learn RxJS
Clear examples, explanations, and resources for RxJS.
By @btroncone
Introduction
RxJS is one of the hottest libraries in web development today. Offering a powerful,
functional approach for dealing with events and with integration points into a
growing number of frameworks, libraries, and utilities, the case for learning Rx has
never been more appealing. Couple this with the ability to utilize your knowledge
across nearly any language, having a solid grasp on reactive programming and
what it can offer seems like a no-brainer.
But...
Content
Operators
5
Introduction
Operator Categories
Combination
Conditional
Creation
Error Handling
Multicasting
Filtering
Transformation
Utility
OR...
Understanding Subjects
A Subject is a special type of Observable which shares a single execution path
among observers.
Overview
AsyncSubject
BehaviorSubject
ReplaySubject
Subject
Concepts
Without a solid base knowledge of how Observables work behind the scenes, it's
easy for much of RxJS to feel like 'magic'. This section helps solidify the major
concepts needed to feel comfortable with reactive programming and Observables.
6
Introduction
Recipes
Recipes for common use-cases and interesting solutions with RxJS.
Game Loop
Horizontal Scroll Indicator
HTTP Polling
Progress Bar
Smart Counter
Type Ahead
Introductory Resources
New to RxJS and reactive programming? In addition to the content found on this
site, these excellent articles and videos will help jump start your learning
experience!
Reading
RxJS Introduction - Official Docs
The Introduction to Reactive Programming You've Been Missing - André
Staltz
Videos
Asynchronous Programming: The End of The Loop - Jafar Husain
What is RxJS? - Ben Lesh
Creating Observable from Scratch - Ben Lesh
Introduction to RxJS Marble Testing - Brian Troncone
Introduction to Reactive Programming - André Staltz
Reactive Programming using Observables - Jeremy Lund
Exercises
Functional Programming in JavaScript - Jafar Husain
7
Introduction
Tools
Rx Marbles - Interactive diagrams of Rx Observables - André Staltz
Rx Visualizer - Animated playground for Rx Observables - Misha Moroshko
Reactive.how - Animated cards to learn Reactive Programming - Cédric
Soulas
Rx Visualization - Visualizes programming with RxJS - Mojtaba Zarei
Translations
简体中文
A Note On References
All references included in this GitBook are resources, both free and paid, that
helped me tremendously while learning RxJS. If you come across an article or
video that you think should be included, please use the edit this page link in the
top menu and submit a pull request. Your feedback is appreciated!
8
Operators
9
Operators
timer
Error Handling
catch / catchError
retry
retryWhen
Filtering
audit
auditTime
debounce
debounceTime
distinctUntilChanged
filter
first
ignoreElements
last
sample
single
skip
skipUntil
skipWhile
take
takeUntil
takeWhile
throttle
throttleTime
Multicasting
multicast
publish
share
shareReplay
Transformation
buffer
bufferCount
bufferTime
bufferToggle
bufferWhen
10
Operators
concatMap
concatMapTo
expand
exhaustMap
groupBy
map
mapTo
mergeMap / flatMap
partition
pluck
reduce
scan
switchMap
toArray
window
windowCount
windowTime
windowToggle
windowWhen
Utility
do / tap
delay
delayWhen
finalize / finally
let
repeat
toPromise
timeout
- commonly used
Additional Resources
What Are Operators? - Official Docs
What Operators Are - André Staltz
11
Operators
12
Combination
Combination Operators
The combination operators allow the joining of information from multiple
observables. Order, time, and structure of emitted values is the primary variation
among these operators.
Contents
combineAll
combineLatest
concat
concatAll
forkJoin
merge
mergeAll
pairwise
race
startWith
withLatestFrom
zip
- commonly used
13
combineAll
combineAll
signature: combineAll(project: function): Observable
Examples
( example tests )
( StackBlitz )
14
combineAll
// RxJS v6+
import { take, map, combineAll } from 'rxjs/operators';
import { interval } from 'rxjs';
Additional Resources
combineAll - Official docs
15
combineAll
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/combineA
ll.ts
16
combineLatest
combineLatest
signature: combineLatest(observables: ...Observable,
project: function): Observable
Be aware that combineLatest will not emit an initial value until each
observable emits at least one value. This is the same behavior as
withLatestFrom and can be a gotcha as there will be no output and no error
but one (or more) of your inner observables is likely not functioning as intended, or
a subscription is late.
Lastly, if you are working with observables that only emit one value, or you only
require the last value of each before completion, forkJoin is likely a better
option.
17
combineLatest
Examples
( example tests )
18
combineLatest
// RxJS v6+
import { timer, combineLatest } from 'rxjs';
//when one timer emits, emit the latest values from each timer a
s an array
const combined = combineLatest(timerOne, timerTwo, timerThree);
19
combineLatest
// RxJS v6+
import { timer, combineLatest } from 'rxjs';
20
combineLatest
// RxJS v6+
import { fromEvent, combineLatest } from 'rxjs';
import { mapTo, startWith, scan, tap, map } from 'rxjs/operators'
;
HTML
<div>
<button id='red'>Red</button>
<button id='black'>Black</button>
</div>
<div>Red: <span id="redTotal"></span> </div>
<div>Black: <span id="blackTotal"></span> </div>
<div>Total: <span id="total"></span> </div>
Additional Resources
combineLatest - Official docs
21
combineLatest
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/combineL
atest.ts
22
concat
concat
signature: concat(observables: ...*): Observable
You can think of concat like a line at a ATM, the next transaction (subscription)
cannot start until the previous completes!
Examples
( example tests )
23
concat
// RxJS v6+
import { concat } from 'rxjs/operators';
import { of } from 'rxjs';
//emits 1,2,3
const sourceOne = of(1, 2, 3);
//emits 4,5,6
const sourceTwo = of(4, 5, 6);
//emit values from sourceOne, when complete, subscribe to source
Two
const example = sourceOne.pipe(concat(sourceTwo));
//output: 1,2,3,4,5,6
const subscribe = example.subscribe(val =>
console.log('Example: Basic concat:', val)
);
// RxJS v6+
import { of, concat } from 'rxjs';
//emits 1,2,3
const sourceOne = of(1, 2, 3);
//emits 4,5,6
const sourceTwo = of(4, 5, 6);
//used as static
const example = concat(sourceOne, sourceTwo);
//output: 1,2,3,4,5,6
const subscribe = example.subscribe(val => console.log(val));
24
concat
// RxJS v6+
import { delay, concat } from 'rxjs/operators';
import { of } from 'rxjs';
//emits 1,2,3
const sourceOne = of(1, 2, 3);
//emits 4,5,6
const sourceTwo = of(4, 5, 6);
// RxJS v6+
import { interval, of, concat } from 'rxjs';
25
concat
Additional Resources
concat - Official docs
Combination operator: concat, startWith - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/concat.ts
26
concatAll
concatAll
signature: concatAll(): Observable
Be wary of backpressure when the source emits at a faster pace than inner
observables complete!
Examples
( example tests )
27
concatAll
// RxJS v6+
import { map, concatAll } from 'rxjs/operators';
import { of, interval } from 'rxjs';
28
concatAll
// RxJS v6+
import { map, concatAll } from 'rxjs/operators';
import { interval } from 'rxjs';
29
concatAll
// RxJS v6+
import { take, concatAll } from 'rxjs/operators';
import { interval, of } from 'rxjs/observable/interval';
Related Recipes
Progress Bar
Additional Resources
concatAll - Official docs
Flatten a higher order observable with concatAll in RxJS - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/concatAll.
ts
30
concatAll
31
forkJoin
forkJoin
signature: forkJoin(...args, selector : function):
Observable
If an inner observable does not complete forkJoin will never emit a value!
Be aware that if any of the inner observables supplied to forkJoin error you
will lose the value of any other observables that would or have already completed
if you do not catch the error correctly on the inner observable. If you are only
concerned with all inner observables completing successfully you can catch the
error on the outside.
It's also worth noting that if you have an observable that emits more than one
item, and you are concerned with the previous emissions forkJoin is not the
correct choice. In these cases you may better off with an operator like
combineLatest or zip.
32
forkJoin
Examples
Example 1: Observables completing after different durations
// RxJS v6+
import { delay, take } from 'rxjs/operators';
import { forkJoin, of, interval } from 'rxjs';
/*
when all observables complete, give the last
emitted value from each as an array
*/
const example = forkJoin(
//emit 'Hello' immediately
of('Hello'),
//emit 'World' after 1 second
of('World').pipe(delay(1000)),
//emit 0 after 1 second
interval(1000).pipe(take(1)),
//emit 0...1 in 1 second interval
interval(1000).pipe(take(2)),
//promise that resolves to 'Promise Resolved' after 5 seconds
myPromise('RESULT')
);
//output: ["Hello", "World", 0, 1, "Promise Resolved: RESULT"]
const subscribe = example.subscribe(val => console.log(val));
33
forkJoin
// RxJS v6+
import { mergeMap } from 'rxjs/operators';
import { forkJoin, of } from 'rxjs';
34
forkJoin
// RxJS v6+
import { delay, catchError } from 'rxjs/operators';
import { forkJoin, of, throwError } from 'rxjs';
/*
when all observables complete, give the last
emitted value from each as an array
*/
const example = forkJoin(
//emit 'Hello' immediately
of('Hello'),
//emit 'World' after 1 second
of('World').pipe(delay(1000)),
// throw error
_throw('This will error')
).pipe(catchError(error => of(error)));
//output: 'This will Error'
const subscribe = example.subscribe(val => console.log(val));
35
forkJoin
// RxJS v6+
import { delay, catchError } from 'rxjs/operators';
import { forkJoin, of, throwError } from 'rxjs';
/*
when all observables complete, give the last
emitted value from each as an array
*/
const example = forkJoin(
//emit 'Hello' immediately
of('Hello'),
//emit 'World' after 1 second
of('World').pipe(delay(1000)),
// throw error
_throw('This will error').pipe(catchError(error => of(error)))
);
//output: ["Hello", "World", "This will error"]
const subscribe = example.subscribe(val => console.log(val));
( plunker )
@Injectable()
export class MyService {
makeRequest(value: string, delayDuration: number) {
// simulate http request
return of(`Complete: ${value}`).pipe(
delay(delayDuration)
);
}
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>forkJoin Example</h2>
<ul>
<li> {{propOne}} </li>
36
forkJoin
ngOnInit() {
// simulate 3 requests with different delays
forkJoin(
this._myService.makeRequest('Request One', 2000),
this._myService.makeRequest('Request Two', 1000),
this._myService.makeRequest('Request Three', 3000)
)
.subscribe(([res1, res2, res3]) => {
this.propOne = res1;
this.propTwo = res2;
this.propThree = res3;
});
}
}
Additional Resources
forkJoin - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/observable/ForkJoinObserv
able.ts
37
merge
merge
signature: merge(input: Observable): Observable
Examples
Example 1: merging multiple observables, static method
38
merge
// RxJS v6+
import { mapTo } from 'rxjs/operators';
import { interval, merge } from 'rxjs';
// RxJS v6+
import { merge } from 'rxjs/operators';
import { interval } from 'rxjs';
39
merge
Related Recipes
HTTP Polling
Additional Resources
merge - Official docs
Handling multiple streams with merge - John Linquist
Sharing network requests with merge - André Staltz
Combination operator: merge - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/merge.ts
40
mergeAll
mergeAll
signature: mergeAll(concurrent: number): Observable
Examples
( example tests )
41
mergeAll
// RxJS v6+
import { map, mergeAll } from 'rxjs/operators';
import { of } from 'rxjs';
/*
output:
"Result: 1"
"Result: 2"
"Result: 3"
*/
const subscribe = example.subscribe(val => console.log(val));
( StackBlitz | jsFiddle )
42
mergeAll
// RxJS v6+
import { take, map, delay, mergeAll } from 'rxjs/operators';
import { interval } from 'rxjs';
/*
interval is emitting a value every 0.5s. This value is then b
eing mapped to interval that
is delayed for 1.0s. The mergeAll operator takes an optional
argument that determines how
many inner observables to subscribe to at a time. The rest of
the observables are stored
in a backlog waiting to be subscribe.
*/
const example = source
.pipe(
map(val =>
source.pipe(
delay(1000),
take(3)
)
),
mergeAll(2)
)
.subscribe(val => console.log(val));
/*
The subscription is completed once the operator emits all valu
es.
*/
Additional Resources
mergeAll - Official docs
Flatten a higher order observable with mergeAll in RxJS - André Staltz
43
mergeAll
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/mergeAll.t
s
44
pairwise
pairwise
signature: pairwise(): Observable<Array>
Examples
Example 1:
// RxJS v6+
import { pairwise, take } from 'rxjs/operators';
import { interval } from 'rxjs';
Additional Resources
pairwise - Official docs
45
pairwise
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/pairwise.t
s
46
race
race
signature: race(): Observable
Examples
Example 1: race with 4 observables
// RxJS v6+
import { mapTo } from 'rxjs/operators';
import { interval } from 'rxjs/observable/interval';
import { race } from 'rxjs/observable/race';
47
race
( StackBlitz | jsFiddle )
// RxJS v6+
import { delay, map } from 'rxjs/operators';
import { of, race } from 'rxjs';
Additional Resources
race - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/race.ts
48
startWith
startWith
signature: startWith(an: Values): Observable
Examples
( example tests )
// RxJS v6+
import { startWith } from 'rxjs/operators';
import { of } from 'rxjs';
//emit (1,2,3)
const source = of(1, 2, 3);
//start with 0
const example = source.pipe(startWith(0));
//output: 0,1,2,3
const subscribe = example.subscribe(val => console.log(val));
49
startWith
// RxJS v6+
import { startWith, scan } from 'rxjs/operators';
import { of } from 'rxjs';
// RxJS v6+
import { startWith } from 'rxjs/operators';
import { interval } from 'rxjs';
Related Recipes
50
startWith
Smart Counter
Additional Resources
startWith - Official docs
Displaying initial data with startWith - John Linquist
Clear data while loading with startWith - André Staltz
Combination operator: concat, startWith - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/startWith.t
s
51
withLatestFrom
withLatestFrom
signature: withLatestFrom(other: Observable, project:
Function): Observable
If you want the last emission any time a variable number of observables emits,
try combinelatest!
Examples
Example 1: Latest value from quicker second source
52
withLatestFrom
// RxJS v6+
import { withLatestFrom, map } from 'rxjs/operators';
import { interval } from 'rxjs';
//emit every 5s
const source = interval(5000);
//emit every 1s
const secondSource = interval(1000);
const example = source.pipe(
withLatestFrom(secondSource),
map(([first, second]) => {
return `First Source (5s): ${first} Second Source (1s): ${se
cond}`;
})
);
/*
"First Source (5s): 0 Second Source (1s): 4"
"First Source (5s): 1 Second Source (1s): 9"
"First Source (5s): 2 Second Source (1s): 14"
...
*/
const subscribe = example.subscribe(val => console.log(val));
53
withLatestFrom
// RxJS v6+
import { withLatestFrom, map } from 'rxjs/operators';
import { interval } from 'rxjs';
//emit every 5s
const source = interval(5000);
//emit every 1s
const secondSource = interval(1000);
//withLatestFrom slower than source
const example = secondSource.pipe(
//both sources must emit at least 1 value (5s) before emitting
withLatestFrom(source),
map(([first, second]) => {
return `Source (1s): ${first} Latest From (5s): ${second}`;
})
);
/*
"Source (1s): 4 Latest From (5s): 0"
"Source (1s): 5 Latest From (5s): 0"
"Source (1s): 6 Latest From (5s): 0"
...
*/
const subscribe = example.subscribe(val => console.log(val));
Related Recipes
Progress Bar
Game Loop
Additional Resources
withLatestFrom - Official docs
Combination operator: withLatestFrom - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/withLatest
From.ts
54
withLatestFrom
55
zip
zip
signature: zip(observables: *): Observable
Combined with interval or timer, zip can be used to time output from another
source!
Examples
Example 1: zip multiple observables emitting at alternate intervals
56
zip
// RxJS v6+
import { delay } from 'rxjs/operators';
import { of, zip } from 'rxjs';
// RxJS v6+
import { take } from 'rxjs/operators';
import { interval, zip } from 'rxjs';
//emit every 1s
const source = interval(1000);
//when one observable completes no more values will be emitted
const example = zip(source, source.pipe(take(2)));
//output: [0,0]...[1,1]
const subscribe = example.subscribe(val => console.log(val));
( StackBlitz )
57
zip
// RxJS v6+
import { fromEvent, zip } from 'rxjs';
import { map } from 'rxjs/operators';
zip(documentEvent('mousedown'), documentEvent('mouseup'))
.subscribe(e => console.log(JSON.stringify(e)));
( StackBlitz )
// RxJS v6+
import { fromEvent, zip } from 'rxjs';
import { map } from 'rxjs/operators';
const mouseClickDuration =
zip(
eventTime('mousedown'),
eventTime('mouseup')
).pipe(
map(([start, end]) =>
Math.abs((start.getTime() - end.getTime())))
);
mouseClickDuration.subscribe(console.log);
Additional Resources
zip - Official docs
Combination operator: zip - André Staltz
58
zip
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/zip.ts
59
Conditional
Conditional Operators
For use-cases that depend on a specific condition to be met, these operators do
the trick.
Contents
defaultIfEmpty
every
iif
sequenceequal
60
defaultIfEmpty
defaultIfEmpty
signature: defaultIfEmpty(defaultValue: any): Observable
Examples
Example 1: Default for empty value
// RxJS v6+
import { defaultIfEmpty } from 'rxjs/operators';
import { of } from 'rxjs';
61
defaultIfEmpty
// RxJS v6+
import { defaultIfEmpty } from 'rxjs/operators';
import { empty } from 'rxjs';
Additional Resources
defaultIfEmpty - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/defaultIfE
mpty.ts
62
every
every
signature: every(predicate: function, thisArg: any):
Observable
Examples
Example 1: Some values false
// RxJS v6+
import { every } from 'rxjs/operators';
import { of } from 'rxjs';
//emit 5 values
const source = of(1, 2, 3, 4, 5);
const example = source.pipe(
//is every value even?
every(val => val % 2 === 0)
);
//output: false
const subscribe = example.subscribe(val => console.log(val));
63
every
// RxJS v6+
import { every } from 'rxjs/operators';
import { of } from 'rxjs';
//emit 5 values
const allEvens = of(2, 4, 6, 8, 10);
const example = allEvens.pipe(
//is every value even?
every(val => val % 2 === 0)
);
//output: true
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
every - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/every.ts
64
iif
iif
signature: iif<T, F>(condition: () => boolean, trueResult:
SubscribableOrPromise<T> = EMPTY, falseResult:
SubscribableOrPromise<F> = EMPTY): Observable<T | F>
Examples
Example 1: simple iif
( Stackblitz )
// RxJS v6+
import { iif, of, interval } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
const r$ = of('R');
const x$ = of('X');
interval(1000).pipe(
mergeMap(v =>
iif(
() => v % 4 === 0,
r$,
x$
))
).subscribe(console.log);
//output: R, X, X, X, R, X, X, X, etc...
65
iif
( Stackblitz )
// RxJS v6+
import { fromEvent, iif, of } from 'rxjs';
import { mergeMap, map, throttleTime, filter } from 'rxjs/operat
ors';
fromEvent(document, 'mousemove').pipe(
throttleTime(50),
filter((move: MouseEvent) => move.clientY < 210),
map((move: MouseEvent) => move.clientY),
mergeMap(yCoord =>
iif(
() => yCoord < 110,
r$,
x$
))
).subscribe(console.log);
Additional Resources
iif - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/iif.ts
66
sequenceequal
sequenceEqual
signature: sequenceEqual<T>(compareTo: Observable<T>,
comparor?: (a: T, b: T) => boolean): OperatorFunction<T,
boolean>
Examples
Example 1: simple sequenceEqual
( Stackblitz )
// RxJS v6+
import { of, from } from 'rxjs';
import { sequenceEqual, switchMap } from 'rxjs/operators';
67
sequenceequal
( Stackblitz )
// RxJS v6+
import { from, fromEvent } from 'rxjs';
import { sequenceEqual, map, bufferCount, mergeMap, tap } from '
rxjs/operators';
fromEvent(document, 'keydown')
.pipe(
map((e: KeyboardEvent) => e.key),
tap(v => setResult(v)),
bufferCount(6),
mergeMap(keyDowns =>
from(keyDowns)
.pipe(
sequenceEqual(expectedSequence),
tap(isItQwerty =>
setResult(isItQwerty ? 'WELL DONE!' : 'TYPE AGAIN!'))
))
)
.subscribe(e => console.log(`did you say qwerty? ${e}`));
Additional Resources
sequenceEqual - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/sequence
Equal.ts
68
sequenceequal
69
Creation
Creation Operators
These operators allow the creation of an observable from nearly anything. From
generic to specific use-cases you are free, and encouraged, to turn everything into
a stream.
Contents
create
empty
from
fromEvent
interval
of
range
throw
timer
- commonly used
Additional Resources
Creating Observables From Scratch - André Staltz
70
create
create
signature: create(subscribe: function)
Examples
Example 1: Observable that emits multiple values
// RxJS v6+
import { Observable } from 'rxjs';
/*
Create an observable that emits 'Hello' and 'World' on
subscription.
*/
const hello = Observable.create(function(observer) {
observer.next('Hello');
observer.next('World');
});
//output: 'Hello'...'World'
const subscribe = hello.subscribe(val => console.log(val));
71
create
// RxJS v6+
import { Observable } from 'rxjs';
/*
Increment value every 1s, emit even numbers.
*/
const evenNumbers = Observable.create(function(observer) {
let value = 0;
const interval = setInterval(() => {
if (value % 2 === 0) {
observer.next(value);
}
value++;
}, 1000);
Additional Resources
create - Official docs
Creation operators: Create() - André Staltz
Using Observable.create for fine-grained control - Shane Osbourne
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/Generat
eObservable.ts
72
create
73
empty
empty
signature: empty(scheduler: Scheduler): Observable
Examples
Example 1: empty immediately completes
// RxJS v6+
import { empty } from 'rxjs';
//output: 'Complete!'
const subscribe = empty().subscribe({
next: () => console.log('Next'),
complete: () => console.log('Complete!')
});
( StackBlitz )
74
empty
// RxJS v6+
import { interval, fromEvent, merge, empty } from 'rxjs';
import { switchMap, scan, takeWhile, startWith, mapTo } from 'rx
js/operators';
Additional Resources
empty - Official docs
Creation operators: empty, never, and throw - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/EmptyO
bservable.ts
75
empty
76
from
from
signature: from(ish: ObservableInput, mapFn: function,
thisArg: any, scheduler: Scheduler): Observable
For arrays and iterables, all contained values will be emitted as a sequence!
Examples
Example 1: Observable from array
// RxJS v6+
import { from } from 'rxjs';
77
from
// RxJS v6+
import { from } from 'rxjs';
// RxJS v6+
import { from } from 'rxjs';
//works on js collections
const map = new Map();
map.set(1, 'Hi');
map.set(2, 'Bye');
78
from
// RxJS v6+
import { from } from 'rxjs';
Related Recipes
Progress Bar
HTTP Polling
Additional Resources
from - Official docs
Creation operators: from, fromArray, fromPromise - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/from.ts
79
fromEvent
fromEvent
signature: fromEvent(target: EventTargetLike, eventName:
string, selector: function): Observable
Examples
Example 1: Observable from mouse clicks
// RxJS v6+
import { fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';
Related Recipes
Smart Counter
Progress Bar
Game Loop
HTTP Polling
80
fromEvent
Additional Resources
fromEvent - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/FromEv
entObservable.ts
81
interval
interval
signature: interval(period: number, scheduler: Scheduler):
Observable
Examples
Example 1: Emit sequence of values at 1 second interval
// RxJS v6+
import { interval } from 'rxjs';
Additional Resources
interval - Official docs
Creation operators: interval and timer - André Staltz
82
interval
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/interval.t
s
83
of
of / just
signature: of(...values, scheduler: Scheduler): Observable
Examples
Example 1: Emitting a sequence of numbers
// RxJS v6+
import { of } from 'rxjs';
//emits any number of provided values in sequence
const source = of(1, 2, 3, 4, 5);
//output: 1,2,3,4,5
const subscribe = source.subscribe(val => console.log(val));
// RxJS v6+
import { of } from 'rxjs';
//emits values of any type
const source = of({ name: 'Brian' }, [1, 2, 3], function hello()
{
return 'Hello';
});
//output: {name: 'Brian}, [1,2,3], function hello() { return 'He
llo' }
const subscribe = source.subscribe(val => console.log(val));
84
of
Related Recipes
Type Ahead
Additional Resources
of - Official docs
Creation operators: of - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/of.ts
85
range
range
signature: range(start: number, count: number, scheduler:
Scheduler): Observable
Examples
Example 1: Emit range 1-10
// RxJS v6+
import { range } from 'rxjs';
Additional Resources
range - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/range.ts
86
range
87
throw
throw
signature: throw(error: any, scheduler: Scheduler):
Observable
Examples
Example 1: Throw error on subscription
// RxJS v6+
import { throwError } from 'rxjs';
Related Examples
Throwing after 3 retries
Additional Resources
88
throw
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/throwErr
or.ts
89
timer
timer
signature: timer(initialDelay: number | Date, period:
number, scheduler: Scheduler): Observable
Examples
Example 1: timer emits 1 value then completes
// RxJS v6+
import { timer } from 'rxjs';
90
timer
// RxJS v6+
import { timer } from 'rxjs';
/*
timer takes a second argument, how often to emit subsequent va
lues
in this case we will emit first value after 1 second and subse
quent
values every 2 seconds after
*/
const source = timer(1000, 2000);
//output: 0,1,2,3,4,5......
const subscribe = source.subscribe(val => console.log(val));
Related Recipes
HTTP Polling
Additional Resources
timer - Official docs
Creation operators: interval and timer - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/observable/timer.ts
91
Error Handling
Contents
catch / catchError
retry
retryWhen
- commonly used
92
catch / catchError
catch / catchError
signature: catchError(project : function): Observable
Examples
( example tests )
// RxJS v6+
import { throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
//emit error
const source = throwError('This is an error!');
//gracefully handle error, returning observable with error messa
ge
const example = source.pipe(catchError(val => of(`I caught: ${val
}`)));
//output: 'I caught: This is an error'
const subscribe = example.subscribe(val => console.log(val));
93
catch / catchError
// RxJS v6+
import { timer, from, of } from 'rxjs';
import { mergeMap, catchError } from 'rxjs/operators';
Additional Resources
Error handling operator: catch - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/catchErro
r.ts
94
retry
retry
signature: retry(number: number): Observable
Examples
Example 1: Retry 2 times on error
95
retry
// RxJS v6+
import { interval, of, throwError } from 'rxjs';
import { mergeMap, retry } from 'rxjs/operators';
});
Additional Resources
retry - Official docs
Error handling operator: retry and retryWhen - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/retry.ts
96
retry
97
retryWhen
retryWhen
signature: retryWhen(receives: (errors: Observable) =>
Observable, the: scheduler): Observable
Examples
Example 1: Trigger retry after specified duration
98
retryWhen
// RxJS v6+
import { timer, interval } from 'rxjs';
import { map, tap, retryWhen, delayWhen } from 'rxjs/operators';
( StackBlitz )
99
retryWhen
100
retryWhen
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
constructor(private _appService: AppService) {}
ngOnInit() {
this._appService
.getData(500)
.pipe(
retryWhen(genericRetryStrategy()),
catchError(error => of(error))
)
.subscribe(console.log);
}, 8000);
}
}
101
retryWhen
Additional Resources
retryWhen - Official docs
Error handling operator: retry and retryWhen - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/retryWhe
n.ts
102
Multicasting
Multicasting Operators
In RxJS observables are cold, or unicast by default. These operators can make an
observable hot, or multicast, allowing side-effects to be shared among multiple
subscribers.
Contents
publish
multicast
share
shareReplay
- commonly used
Additional Resources
Hot vs Cold Observables - Ben Lesh
Unicast v Multicast - GitHub Discussion
Demystifying Hot and Cold Observables - André Staltz
103
publish
publish
signature: publish() : ConnectableObservable
Examples
Example 1: Connect observable after subscribers
104
publish
// RxJS v6+
import { interval } from 'rxjs';
import { publish, tap } from 'rxjs/operators';
/*
source will not emit values until connect() is called
output: (after 5s)
"Do Something!"
"Subscriber One: 0"
"Subscriber Two: 0"
"Do Something!"
"Subscriber One: 1"
"Subscriber Two: 1"
*/
const subscribe = example.subscribe(val =>
console.log(`Subscriber One: ${val}`)
);
const subscribeTwo = example.subscribe(val =>
console.log(`Subscriber Two: ${val}`)
);
Additional Resources
publish - Official docs
105
publish
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/publish.ts
106
multicast
multicast
signature: multicast(selector: Function): Observable
Examples
Example 1: multicast with standard Subject
107
multicast
// RxJS v6+
import { Subject, interval } from 'rxjs';
import { take, tap, multicast, mapTo } from 'rxjs/operators';
108
multicast
// RxJS v6+
import { interval, ReplaySubject } from 'rxjs';
import { take, multicast, tap, mapTo } from 'rxjs/operators';
setTimeout(() => {
/*
subscriber will receieve all previous values on subscription
because
of ReplaySubject
*/
const subscriber = multi.subscribe(val => console.group(val));
}, 5000);
Additional Resources
multicast - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/multicast.t
s
109
multicast
110
share
share
signature: share(): Observable
Examples
Example 1: Multiple subscribers sharing source
111
share
// RxJS v6+
import { timer } from 'rxjs';
import { tap, mapTo, share } from 'rxjs/operators';
//emit value in 1s
const source = timer(1000);
//log side effect, emit result
const example = source.pipe(
tap(() => console.log('***SIDE EFFECT***')),
mapTo('***RESULT***')
);
/*
***NOT SHARED, SIDE EFFECT WILL BE EXECUTED TWICE***
output:
"***SIDE EFFECT***"
"***RESULT***"
"***SIDE EFFECT***"
"***RESULT***"
*/
const subscribe = example.subscribe(val => console.log(val));
const subscribeTwo = example.subscribe(val => console.log(val));
Related Recipes
112
share
Progress Bar
Game Loop
Additional Resources
share - Official docs
Sharing streams with share - John Linquist
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/share.ts
113
shareReplay
shareReplay
signature: shareReplay(bufferSize?: number, windowTime?:
number, scheduler?I IScheduler): Observable
For instance, suppose you have an observable that emits the last visited url. In the
first example we are going to use share :
// nothing logged
const lateSubscriber = lastUrl.subscribe(console.log);
114
shareReplay
// logged: 'my-path'
const lateSubscriber = lastUrl.subscribe(console.log);
Note that this is similar behavior to what you would see if you subscribed a
ReplaySubject to the lastUrl stream, then subscribed to that Subject :
115
shareReplay
In fact, if we dig into the source code we can see a very similar technique is being
used. When a subscription is made, shareReplay will subscribe to the source,
sending values through an internal ReplaySubject :
( source )
116
shareReplay
return () => {
refCount--;
innerSub.unsubscribe();
if (subscription && refCount === 0 && isComplete) {
subscription.unsubscribe();
}
};
};
}
Examples
117
shareReplay
( Stackblitz )
// RxJS v6+
import { Subject, ReplaySubject } from 'rxjs';
import { pluck, share, shareReplay, tap } from 'rxjs/operators';
Additional Resources
shareReplay - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/shareRep
lay.ts
118
Filtering
Filtering Operators
In a push based approach, picking and choosing how and when to accept items is
important. These operators provide techniques for accepting values from an
observable source and dealing with backpressure.
Contents
audit
auditTime
debounce
debounceTime
distinctUntilChanged
filter
first
ignoreElements
last
sample
single
skip
skipUntil
skipWhile
take
takeUntil
takeWhile
throttle
throttleTime
- commonly used
119
audit
audit
signature: audit(durationSelector: (value) => Observable |
Promise): Observable
Additional Resources
audit - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/audit.ts
120
auditTime
auditTime
signature: auditTime(duration: number, scheduler?:
Scheduler): Observable
If you want the timer to reset whenever a new event occurs on the soruce
observable, you can use debounceTime
Examples
Example 1: Emit clicks at a rate of at most one click per second
( stackBlitz )
121
auditTime
Additional Resources
auditTime - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/auditTime
.ts
122
debounce
debounce
signature: debounce(durationSelector: function): Observable
Examples
Example 1: Debounce on timer
123
debounce
// RxJS v6+
import { of, timer } from 'rxjs';
import { debounce } from 'rxjs/operators';
/*
Only emit values after a second has passed between the last
emission,
throw away all other values
*/
const debouncedExample = example.pipe(debounce(() => timer(1000))
);
/*
In this example, all values but the last will be omitted
output: 'Last will display'
*/
const subscribe = debouncedExample.subscribe(val => console.log(
val));
124
debounce
// RxJS v6+
import { interval, timer } from 'rxjs';
import { debounce } from 'rxjs/operators';
Additional Resources
debounce - Official docs
Transformation operator: debounce and debounceTime - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/debounce
.ts
125
debounceTime
debounceTime
signature: debounceTime(dueTime: number, scheduler:
Scheduler): Observable
This operator is popular in scenarios such as type-ahead where the rate of user
input must be controlled!
Examples
Example 1: Debouncing based on time between input
126
debounceTime
// RxJS v6+
import { fromEvent, timer } from 'rxjs';
import { debounceTime, map } from 'rxjs/operators';
//log values
const subscribe = debouncedInput.subscribe(val => {
console.log(`Debounced Input: ${val}`);
});
Related Recipes
Type Ahead
Additional Resources
debounceTime - Official docs
Transformation operator: debounce and debounceTime - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/debounce
Time.ts
127
distinctUntilChanged
distinctUntilChanged
signature: distinctUntilChanged(compare: function):
Observable
Examples
Example 1: distinctUntilChanged with basic values
// RxJS v6+
import { from } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
128
distinctUntilChanged
// RxJS v6+
import { from } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
Related Recipes
Type Ahead
Additional Resources
distinctUntilChanged - Official docs
Filtering operator: distinct and distinctUntilChanged - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/distinctUn
tilChanged.ts
129
filter
filter
signature: filter(select: Function, thisArg: any):
Observable
If you would like to complete an observable when a condition fails, check out
takeWhile!
Examples
Example 1: filter for even numbers
// RxJS v6+
import { from } from 'rxjs';
import { filter } from 'rxjs/operators';
//emit (1,2,3,4,5)
const source = from([1, 2, 3, 4, 5]);
//filter out non-even numbers
const example = source.pipe(filter(num => num % 2 === 0));
//output: "Even number: 2", "Even number: 4"
const subscribe = example.subscribe(val => console.log(`Even num
ber: ${val}`));
130
filter
// RxJS v6+
import { from } from 'rxjs';
import { filter } from 'rxjs/operators';
// RxJS v6+
import { interval } from 'rxjs';
import { filter } from 'rxjs/operators';
Related Recipes
HTTP Polling
131
filter
Game Loop
Additional Resources
filter - Official docs
Adding conditional logic with filter - John Linquist
Filtering operator: filter - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/filter.ts
132
first
first
signature: first(predicate: function, select: function)
Examples
( example tests )
// RxJS v6+
import { from } from 'rxjs';
import { first } from 'rxjs/operators';
133
first
// RxJS v6+
import { from } from 'rxjs';
import { first } from 'rxjs/operators';
// RxJS v6+
import { from } from 'rxjs';
import { first } from 'rxjs/operators';
Additional Resources
first - Official docs
Filtering operator: take, first, skip - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/first.ts
134
first
135
ignoreElements
ignoreElements
signature: ignoreElements(): Observable
Examples
Example 1: Ignore all elements from source
// RxJS v6+
import { interval } from 'rxjs';
import { take, ignoreElements } from 'rxjs/operators';
136
ignoreElements
// RxJS v6+
import { interval, throwError, of } from 'rxjs';
import { mergeMap, ignoreElements } from 'rxjs/operators';
Additional Resources
ignoreElements - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/ignoreEle
ments.ts
137
last
last
signature: last(predicate: function): Observable
Examples
Example 1: Last value in sequence
// RxJS v6+
import { from } from 'rxjs';
import { last } from 'rxjs/operators';
138
last
// RxJS v6+
import { from } from 'rxjs';
import { last } from 'rxjs/operators';
// RxJS v6+
import { from } from 'rxjs';
import { last } from 'rxjs/operators';
Additional Resources
last - Official docs
Filtering operator: takeLast, last - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/last.ts
139
last
140
sample
sample
signature: sample(sampler: Observable): Observable
Examples
Example 1: Sample source every 2 seconds
// RxJS v6+
import { interval } from 'rxjs';
import { sample } from 'rxjs/operators';
141
sample
// RxJS v6+
import { interval, zip, from } from 'rxjs';
import { sample } from 'rxjs/operators';
// RxJS v6+
import { fromEvent, merge } from 'rxjs';
import { sample, mapTo } from 'rxjs/operators';
Additional Resources
sample - Official docs
142
sample
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/sample.ts
143
single
single
signature: single(a: Function): Observable
Examples
Example 1: Emit first number passing predicate
// RxJS v6+
import { from } from 'rxjs';
import { single } from 'rxjs/operators';
//emit (1,2,3,4,5)
const source = from([1, 2, 3, 4, 5]);
//emit one item that matches predicate
const example = source.pipe(single(val => val === 4));
//output: 4
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
single - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/single.ts
144
single
145
skip
skip
signature: skip(the: Number): Observable
You could mimic skip by using filter with indexes. Ex. .filter((val,
index) => index > 1)
Examples
Example 1: Skipping values before emission
146
skip
// RxJS v6+
import { interval } from 'rxjs';
import { skip } from 'rxjs/operators';
//emit every 1s
const source = interval(1000);
//skip the first 5 emitted values
const example = source.pipe(skip(5));
//output: 5...6...7...8........
const subscribe = example.subscribe(val => console.log(val));
// RxJS v6+
import { from } from 'rxjs';
import { skip, filter } from 'rxjs/operators';
// 3,4,5...
const skipObs = numArrayObs.pipe(skip(2)).subscribe(console.log);
// 3,4,5...
const filterObs = numArrayObs
.pipe(filter((val, index) => index > 1))
.subscribe(console.log);
//Same output!
Additional Resources
skip - Official docs
Filtering operator: take, first, skip - André Staltz
147
skip
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/skip.ts
148
skipUntil
skipUntil
signature: skipUntil(the: Observable): Observable
Examples
Example 1: Skip until observable emits
// RxJS v6+
import { interval, timer } from 'rxjs';
import { skipUntil } from 'rxjs/operators';
//emit every 1s
const source = interval(1000);
//skip emitted values from source until inner observable emits (
6s)
const example = source.pipe(skipUntil(timer(6000)));
//output: 5...6...7...8........
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
skipUntil - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/skipUntil.t
s
149
skipUntil
150
skipWhile
skipWhile
signature: skipWhile(predicate: Function): Observable
Examples
Example 1: Skip while values below threshold
// RxJS v6+
import { interval } from 'rxjs';
import { skipWhile } from 'rxjs/operators';
//emit every 1s
const source = interval(1000);
//skip emitted values from source while value is less than 5
const example = source.pipe(skipWhile(val => val < 5));
//output: 5...6...7...8........
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
skipWhile - Official docs
151
skipWhile
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/skipWhile
.ts
152
take
take
signature: take(count: number): Observable
take is the opposite of skip where take will take the first n number of
emissions while skip will skip the first n number of emissions.
Examples
Example 1: Take 1 value from source
153
take
// RxJS v6+
import { of } from 'rxjs';
import { take } from 'rxjs/operators';
//emit 1,2,3,4,5
const source = of(1, 2, 3, 4, 5);
//take the first emitted value then complete
const example = source.pipe(take(1));
//output: 1
const subscribe = example.subscribe(val => console.log(val));
// RxJS v6+
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';
(StackBlitz | jsFiddle)
<div id="locationDisplay">
Where would you click first?
</div>
154
take
// RxJS v6+
import { fromEvent } from 'rxjs';
import { take, tap } from 'rxjs/operators';
Additional Resources
take - Official docs
Filtering operator: take, first, skip - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/take.ts
155
takeUntil
takeUntil
signature: takeUntil(notifier: Observable): Observable
Examples
Example 1: Take values until timer emits
// RxJS v6+
import { interval, timer } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
156
takeUntil
// RxJS v6+
import { interval } from 'rxjs/observable/interval';
import { takeUntil, filter, scan, map, withLatestFrom } from 'rx
js/operators';
Additional Resources
takeUntil - Official docs
157
takeUntil
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/takeUntil.t
s
158
takeWhile
takeWhile
signature: takeWhile(predicate: function(value, index):
boolean): Observable
Examples
Example 1: Take values under limit
// RxJS v6+
import { of } from 'rxjs';
import { takeWhile } from 'rxjs/operators';
//emit 1,2,3,4,5
const source = of(1, 2, 3, 4, 5);
//allow values until value from source is greater than 4, then c
omplete
const example = source.pipe(takeWhile(val => val <= 4));
//output: 1,2,3,4
const subscribe = example.subscribe(val => console.log(val));
159
takeWhile
// RxJS v6+
import { of } from 'rxjs';
import { takeWhile, filter } from 'rxjs/operators';
// output: [3, 3, 3, 3, 3, 3, 3]
source
.pipe(filter(it => it === 3))
.subscribe(val => console.log('filter', val));
Related Recipes
Smart Counter
Additional Resources
takeWhile - Official docs
Completing a stream with takeWhile - John Linquist
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/takeWhile
.ts
160
throttle
throttle
signature: throttle(durationSelector: function(value):
Observable | Promise): Observable
Examples
Example 1: Throttle for 2 seconds, based on second observable
// RxJS v6+
import { interval } from 'rxjs';
import { throttle } from 'rxjs/operators';
161
throttle
// RxJS v6+
import { interval } from 'rxjs';
import { throttle, map } from 'rxjs/operators';
Additional Resources
throttle - Official docs
Filtering operator: throttle and throttleTime - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/throttle.ts
162
throttleTime
throttleTime
signature: throttleTime(duration: number, scheduler:
Scheduler): Observable
Examples
Example 1: Receive latest value every 5 seconds
// RxJS v6+
import { interval } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
163
throttleTime
// RxJS v6+
import { interval, merge } from 'rxjs';
import { throttleTime, ignoreElements } from 'rxjs/operators';
Related Recipes
Horizontal Scroll Indicator
Additional Resources
throttleTime - Official docs
Filtering operator: throttle and throttleTime - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/throttleTi
me.ts
164
Transformation
Transformation Operators
Transforming values as they pass through the operator chain is a common task.
These operators provide transformation techniques for nearly any use-case you
will encounter.
Contents
buffer
bufferCount
bufferTime
bufferToggle
bufferWhen
concatMap
concatMapTo
exhaustMap
expand
groupBy
map
mapTo
mergeMap / flatMap
partition
pluck
reduce
scan
switchMap
toArray
window
windowCount
windowTime
windowToggle
windowWhen
- commonly used
165
Transformation
166
buffer
buffer
signature: buffer(closingNotifier: Observable): Observable
Examples
Example 1: Buffer until document click
167
buffer
// RxJS v6+
import { interval, fromEvent } from 'rxjs';
import { buffer } from 'rxjs/operators';
Related Recipes
Game Loop
Additional Resources
buffer - Official docs
Transformation operator: buffer - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/buffer.ts
168
bufferCount
bufferCount
signature: bufferCount(bufferSize: number,
startBufferEvery: number = null): Observable
Examples
Example 1: Collect buffer and emit after specified number of values
// RxJS v6+
import { interval } from 'rxjs';
import { bufferCount } from 'rxjs/operators';
169
bufferCount
// RxJS v6+
import { interval } from 'rxjs';
import { bufferCount } from 'rxjs/operators';
( StackBlitz )
170
bufferCount
// RxJS v6+
import { fromEvent, of } from 'rxjs';
import { bufferCount, map, mergeMap, tap } from 'rxjs/operators';
fromEvent(document, 'keydown')
.pipe(
map((e: KeyboardEvent) => e.key),
bufferCount(5),
mergeMap(fakeKeyPressesPost)
).subscribe();
Additional Resources
bufferCount - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/bufferCou
nt.ts
171
bufferTime
bufferTime
signature: bufferTime(bufferTimeSpan: number,
bufferCreationInterval: number, scheduler: Scheduler):
Observable
Examples
Example 1: Buffer for 2 seconds
// RxJS v6+
import { interval } from 'rxjs';
import { bufferTime } from 'rxjs/operators';
172
bufferTime
// RxJS v6+
import { interval } from 'rxjs';
import { bufferTime } from 'rxjs/operators';
Additional Resources
bufferTime - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/bufferTim
e.ts
173
bufferToggle
bufferToggle
signature: bufferToggle(openings: Observable,
closingSelector: Function): Observable
Examples
Example 1: Toggle buffer on and off at interval
174
bufferToggle
// RxJS v6+
import { interval } from 'rxjs';
import { bufferToggle } from 'rxjs/operators';
( StackBlitz )
175
bufferToggle
fromEvent(document, 'mousemove')
.pipe(
bufferToggle(
fromEvent(document, 'mousedown'),
_ => fromEvent(document, 'mouseup')
)
)
.subscribe(console.log)
Additional Resources
bufferToggle - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/bufferTog
gle.ts
176
bufferWhen
bufferWhen
signature: bufferWhen(closingSelector: function):
Observable
Examples
Example 1: Emit buffer based on interval
// RxJS v6+
import { interval } from 'rxjs';
import { bufferWhen } from 'rxjs/operators';
Additional Resources
177
bufferWhen
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/bufferWh
en.ts
178
concatMap
concatMap
signature: concatMap(project: function, resultSelector:
function): Observable
Examples
Example 1: Demonstrating the difference between concatMap and
mergeMap
( StackBlitz )
179
concatMap
// RxJS v6+
import { of } from 'rxjs';
import { concatMap, delay, mergeMap } from 'rxjs/operators';
180
concatMap
// RxJS v6+
import { of } from 'rxjs';
import { concatMap } from 'rxjs/operators';
181
concatMap
// RxJS v6+
import { of } from 'rxjs';
import { concatMap } from 'rxjs/operators';
Additional Resources
concatMap - Official docs
Use RxJS concatMap to map and concat higher order observables -
André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/concatMa
p.ts
182
concatMapTo
concatMapTo
signature: concatMapTo(observable: Observable,
resultSelector: function): Observable
Examples
Example 1: Map to basic observable (simulating request)
( StackBlitz )
// RxJS v6+
import { of, interval } from 'rxjs';
import { concatMapTo, delay, take } from 'rxjs/operators';
183
concatMapTo
// RxJS v6+
import { interval } from 'rxjs';
import { concatMapTo, take } from 'rxjs/operators';
//emit value every 2 seconds
const interval$ = interval(2000);
//emit value every second for 5 seconds
const source = interval(1000).pipe(take(5));
/*
***Be Careful***: In situations like this where the source emi
ts at a faster pace
than the inner observable completes, memory issues can arise.
(interval emits every 1 second, basicTimer completes every 5)
*/
// basicTimer will complete after 5 seconds, emitting 0,1,2,3,4
const example = interval$.pipe(
concatMapTo(
source,
(firstInterval, secondInterval) => `${firstInterval} ${secon
dInterval}`
)
);
/*
output: 0 0
0 1
0 2
0 3
0 4
1 0
1 1
continued...
*/
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
concatMapTo - Official docs
184
concatMapTo
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/concatMa
pTo.ts
185
exhaustMap
exhaustMap
signature: exhaustMap(project: function, resultSelector:
function): Observable
Examples
Example 1: exhaustMap with interval
186
exhaustMap
// RxJS v6+
import { interval, merge, of } from 'rxjs';
import { delay, take, exhaustMap } from 'rxjs/operators';
187
exhaustMap
// RxJS v6+
import { interval } from 'rxjs';
import { exhaustMap, tap, take } from 'rxjs/operators';
Output:
Emission of first interval: 0
0
1
Emission of first interval: 3
0
1
Emission of first interval: 6
0
1
Emission of first interval: 9
0
1
*/
.subscribe(s => console.log(s));
188
exhaustMap
Outside Examples
exhaustMap for login effect in @ngrx example app
( Source )
@Effect()
login$ = this.actions$.pipe(
ofType(AuthActionTypes.Login),
map((action: Login) => action.payload),
exhaustMap((auth: Authenticate) =>
this.authService
.login(auth)
.pipe(
map(user => new LoginSuccess({ user })),
catchError(error => of(new LoginFailure(error)))
)
)
);
Additional Resources
exhaustMap - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/exhaustM
ap.ts
189
expand
expand
signature: expand(project: function, concurrent: number,
scheduler: Scheduler): Observable
Examples
Example 1: Add one for each invocation
190
expand
// RxJS v6+
import { interval, of } from 'rxjs';
import { expand, take } from 'rxjs/operators';
//emit 2
const source = of(2);
const example = source.pipe(
//recursively call supplied function
expand(val => {
//2,3,4,5,6
console.log(`Passed value: ${val}`);
//3,4,5,6
return of(1 + val);
}),
//call 5 times
take(5)
);
/*
"RESULT: 2"
"Passed value: 2"
"RESULT: 3"
"Passed value: 3"
"RESULT: 4"
"Passed value: 4"
"RESULT: 5"
"Passed value: 5"
"RESULT: 6"
"Passed value: 6"
*/
//output: 2,3,4,5,6
const subscribe = example.subscribe(val => console.log(`RESULT:
${val}`));
Related Recipes
Game Loop
Additional Resources
191
expand
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/expand.ts
192
groupBy
groupBy
signature: groupBy(keySelector: Function, elementSelector:
Function): Observable
Examples
Example 1: Group by property
193
groupBy
// RxJS v6+
import { from } from 'rxjs';
import { groupBy, mergeMap, toArray } from 'rxjs/operators';
const people = [
{ name: 'Sue', age: 25 },
{ name: 'Joe', age: 30 },
{ name: 'Frank', age: 25 },
{ name: 'Sarah', age: 35 }
];
//emit each person
const source = from(people);
//group by age
const example = source.pipe(
groupBy(person => person.age),
// return each item in group as array
mergeMap(group => group.pipe(toArray()))
);
/*
output:
[{age: 25, name: "Sue"},{age: 25, name: "Frank"}]
[{age: 30, name: "Joe"}]
[{age: 35, name: "Sarah"}]
*/
const subscribe = example.subscribe(val => console.log(val));
Additional Resources
groupBy - Official docs
Group higher order observables with RxJS groupBy - André Staltz
Use groupBy in real RxJS applications - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/groupBy.t
s
194
groupBy
195
map
map
signature: map(project: Function, thisArg: any): Observable
Examples
Example 1: Add 10 to each number
// RxJS v6+
import { from } from 'rxjs';
import { map } from 'rxjs/operators';
//emit (1,2,3,4,5)
const source = from([1, 2, 3, 4, 5]);
//add 10 to each value
const example = source.pipe(map(val => val + 10));
//output: 11,12,13,14,15
const subscribe = example.subscribe(val => console.log(val));
196
map
// RxJS v6+
import { from } from 'rxjs';
import { map } from 'rxjs/operators';
Related Recipes
Smart Counter
Game Loop
HTTP Polling
Type Ahead
Additional Resources
map - Official docs
map vs flatMap - Ben Lesh
Transformation operator: map and mapTo - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/map.ts
197
mapTo
mapTo
signature: mapTo(value: any): Observable
Examples
Example 1: Map every emission to string
// RxJS v6+
import { interval } from 'rxjs';
import { mapTo } from 'rxjs/operators';
198
mapTo
// RxJS v6+
import { fromEvent } from 'rxjs';
import { mapTo } from 'rxjs/operators';
Related Recipes
HTTP Polling
Smart Counter
Additional Resources
mapTo - Official docs
Changing behavior with mapTo - John Linquist
Transformation operator: map and mapTo - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/mapTo.ts
199
mergeMap / flatMap
mergeMap
signature: mergeMap(project: function: Observable,
resultSelector: function: any, concurrent: number):
Observable
For instance, when using switchMap each inner subscription is completed when
the source emits, allowing only one active inner subscription. In contrast,
mergeMap allows for multiple inner subscriptions to be active at a time. Because
of this, one of the most common use-case for mergeMap is requests that should
not be canceled, think writes rather than reads. Note that if order must be
maintained concatMap is a better option.
200
mergeMap / flatMap
Examples
Example 1: mergeMap with observable
// RxJS v6+
import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
//emit 'Hello'
const source = of('Hello');
//map to inner observable and flatten
const example = source.pipe(mergeMap(val => of(`${val} World!`)))
;
//output: 'Hello World!'
const subscribe = example.subscribe(val => console.log(val));
201
mergeMap / flatMap
// RxJS v6+
import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
//emit 'Hello'
const source = of('Hello');
//mergeMap also emits result of promise
const myPromise = val =>
new Promise(resolve => resolve(`${val} World From Promise!`));
//map to promise and emit result
const example = source.pipe(mergeMap(val => myPromise(val)));
//output: 'Hello World From Promise'
const subscribe = example.subscribe(val => console.log(val));
202
mergeMap / flatMap
// RxJS v6+
import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
/*
you can also supply a second argument which receives the sourc
e value and emitted
value of inner observable or promise
*/
//emit 'Hello'
const source = of('Hello');
//mergeMap also emits result of promise
const myPromise = val =>
new Promise(resolve => resolve(`${val} World From Promise!`));
const example = source.pipe(
mergeMap(
val => myPromise(val),
(valueFromSource, valueFromPromise) => {
return `Source: ${valueFromSource}, Promise: ${valueFromPr
omise}`;
}
)
);
//output: "Source: Hello, Promise: Hello World From Promise!"
const subscribe = example.subscribe(val => console.log(val));
203
mergeMap / flatMap
// RxJS v6+
import { interval } from 'rxjs';
import { mergeMap, take } from 'rxjs/operators';
//concurrent
2
)
);
/*
Output:
[0, 0, 0, 0] <--1st inner observable
[1, 1, 0, 0] <--2nd inner observable
[0, 0, 1, 1] <--1st inner observable
[1, 1, 1, 1] <--2nd inner observable
[2, 2, 0, 0] <--3rd inner observable
[3, 3, 0, 0] <--4th inner observable
*/
const subscribe = example.subscribe(val => console.log(val));
Related Recipes
HTTP Polling
Additional Resources
mergeMap - Official docs
map vs flatMap - Ben Lesh
Async requests and responses in RxJS - André Staltz
204
mergeMap / flatMap
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/mergeMa
p.ts
205
partition
partition
signature: partition(predicate: function: boolean, thisArg:
any): [Observable, Observable]
Examples
Example 1: Split even and odd numbers
206
partition
// RxJS v6+
import { from, merge } from 'rxjs';
import { partition, map } from 'rxjs/operators';
207
partition
// RxJS v6+
import { merge, of, from } from 'rxjs';
import { map, partition, catchError } from 'rxjs/operators';
Additional Resources
partition - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/partition.t
s
208
partition
209
pluck
pluck
signature: pluck(properties: ...args): Observable
Examples
Example 1: Pluck object property
// RxJS v6+
import { from } from 'rxjs';
import { pluck } from 'rxjs/operators';
210
pluck
// RxJS v6+
import { from } from 'rxjs';
import { pluck } from 'rxjs/operators';
Additional Resources
pluck - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/pluck.ts
211
reduce
reduce
signature: reduce(accumulator: function, seed: any):
Observable
If you need the current accumulated value on each emission, try scan!
Examples
Example 1: Sum a stream of numbers
// RxJS v6+
import { of } from 'rxjs';
import { reduce } from 'rxjs/operators';
Additional Resources
reduce - Official docs
212
reduce
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/reduce.ts
213
scan
scan
signature: scan(accumulator: function, seed: any):
Observable
Examples
Example 1: Sum over time
( StackBlitz )
// RxJS v6+
import { of } from 'rxjs';
import { scan } from 'rxjs/operators';
214
scan
// RxJS v6+
import { Subject } from 'rxjs';
import { scan } from 'rxjs/operators';
( StackBlitz )
// RxJS v6+
import { interval } from 'rxjs';
import { scan, map, distinctUntilChanged } from 'rxjs/operators';
215
scan
( StackBlitz )
// RxJS v6+
import { interval, of } from 'rxjs';
import { scan, delay, repeat, mergeMap } from 'rxjs/operators';
// output:
// ['response'],
// ['response','response'],
// ['response','response','response'],
// etc...
interval(1000)
.pipe(
mergeMap(_ => fakeRequest),
scan<string>((allResponses, currentResponse) =>
[...allResponses, currentResponse], []),
)
.subscribe(console.log);
Related Recipes
Smart Counter
Progress Bar
Additional Resources
scan - Official docs
Aggregating streams with reduce and scan using RxJS - Ben Lesh
Updating data with scan - John Linquist
Transformation operator: scan - André Staltz
216
scan
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/scan.ts
217
switchMap
switchMap
signature: switchMap(project: function: Observable,
resultSelector: function(outerValue, innerValue, outerIndex,
innerIndex): any): Observable
If you would like more than one inner subscription to be maintained, try
mergeMap !
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, for instance if you used mergeMap with an interval and
forgot to properly dispose of inner subscriptions. Remember, switchMap
maintains only one inner subscription at a time, this can be seen clearly in the first
example.
218
switchMap
Examples
Example 1: Restart interval every 5 seconds
// RxJS v6+
import { timer, interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
219
switchMap
// RxJS v6+
import { interval, fromEvent } from 'rxjs';
import { switchMap, mapTo } from 'rxjs/operators';
220
switchMap
// RxJS v6+
import { timer, interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
( StackBlitz )
221
switchMap
// RxJS v6+
import { interval, fromEvent, merge, empty } from 'rxjs';
import { switchMap, scan, takeWhile, startWith, mapTo } from 'rx
js/operators';
HTML
<h4>
Time remaining: <span id="remaining"></span>
</h4>
<button id="pause">
Pause Timer
</button>
<button id="resume">
Resume Timer
</button>
222
switchMap
Related Recipes
Smart Counter
Progress Bar
HTTP Polling
Type Ahead
Additional Resources
switchMap - Official docs
Avoiding switchMap-Related Bugs - Nicholas Jamieson
Starting a stream with switchMap - John Linquist
Use RxJS switchMap to map and flatten higher order observables -
André Staltz
Use switchMap as a safe default to flatten observables in RxJS - André
Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/switchMa
p.ts
223
toArray
toArray
signature: toArray<T>(): OperatorFunction<T, T[]>
Examples
Example 1: get values emitted by interval as an array when interval
completes
( StackBlitz )
// RxJS v6+
import { interval } from 'rxjs';
import { toArray, take } from 'rxjs/operators';
interval(100)
.pipe(
take(10),
toArray()
)
.subscribe(console.log);
// output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Additional Resources
toArray - Official docs
224
toArray
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/toArray.ts
225
window
window
signature: window(windowBoundaries: Observable): Observable
Examples
Example 1: Open window specified by inner observable
// RxJS v6+
import { timer, interval } from 'rxjs';
import { window, scan, mergeAll } from 'rxjs/operators';
226
window
Additional Resources
window - Official docs
Split an RxJS observable with window - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/window.ts
227
windowCount
windowCount
signature: windowCount(windowSize: number,
startWindowEvery: number): Observable
Examples
Example 1: Start new window every x items emitted
228
windowCount
// RxJS v6+
import { interval } from 'rxjs';
import { windowCount, mergeAll, tap } from 'rxjs/operators';
//emit every 1s
const source = interval(1000);
const example = source.pipe(
//start new window every 4 emitted values
windowCount(4),
tap(_ => console.log('NEW WINDOW!'))
);
Additional Resources
windowCount - Official docs
229
windowCount
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/windowC
ount.ts
230
windowTime
windowTime
signature: windowTime(windowTimeSpan: number,
windowCreationInterval: number, scheduler: Scheduler):
Observable
Examples
Example 1: Open new window every specified duration
231
windowTime
// RxJS v6+
import { timer } from 'rxjs';
import { windowTime, tap, mergeAll } from 'rxjs/operators';
Additional Resources
windowTime - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/windowTi
me.ts
232
windowTime
233
windowToggle
windowToggle
signature: windowToggle(openings: Observable,
closingSelector: function(value): Observable): Observable
Examples
Example 1: Toggle window at increasing interval
234
windowToggle
// RxJS v6+
import { timer, interval } from 'rxjs';
import { tap, windowToggle, mergeAll } from 'rxjs/operators';
Additional Resources
windowToggle - Official docs
Split an RxJS observable conditionally with windowToggle - André
235
windowToggle
Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/windowTo
ggle.ts
236
windowWhen
windowWhen
signature: windowWhen(closingSelector: function():
Observable): Observable
Examples
Example 1: Open and close window at interval
237
windowWhen
// RxJS v6+
import { interval, timer } from 'rxjs';
import { windowWhen, tap, mergeAll } from 'rxjs/operators';
Additional Resources
windowWhen - Official docs
238
windowWhen
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/windowW
hen.ts
239
Utility
Utility Operators
From logging, handling notifications, to setting up schedulers, these operators
provide helpful utilities in your observable toolkit.
Contents
do / tap
delay
delayWhen
dematerialize
finalize / finally
let
repeat
timeout
toPromise
- commonly used
240
do / tap
do / tap
signature: do(nextOrObserver: function, error: function,
complete: function): Observable
Examples
Example 1: Logging with do
241
do / tap
// RxJS v6+
import { of } from 'rxjs';
import { tap, map } from 'rxjs/operators';
Related Recipes
Horizontal Scroll Indicator
Type Ahead
Additional Resources
do - Official docs
Logging a stream with do - John Linquist
Utility operator: do - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/do.ts
242
delay
delay
signature: delay(delay: number | Date, scheduler:
Scheduler): Observable
Examples
Example 1: Delay for increasing durations
243
delay
// RxJS v6+
import { of, merge } from 'rxjs';
import { mapTo, delay } from 'rxjs/operators';
Related Recipes
Progress Bar
Additional Resources
delay - Official docs
Transformation operator: delay and delayWhen - André Staltz
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/delay.ts
244
delay
245
delayWhen
delayWhen
signature: delayWhen(selector: Function, sequence:
Observable): Observable
Examples
Example 1: Delay based on observable
// RxJS v6+
import { interval, timer } from 'rxjs';
import { delayWhen } from 'rxjs/operators';
Additional Resources
246
delayWhen
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/delayWhe
n.ts
247
dematerialize
dematerialize
signature: dematerialize(): Observable
Examples
Example 1: Converting notifications to values
// RxJS v6+
import { from, Notification } from 'rxjs';
import { dematerialize } from 'rxjs/operators';
248
dematerialize
Additional Resources
dematerialize - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/demteriali
ze.ts
249
finalize / finally
finalize / finally
signature: finalize(callback: () => void)
Examples
Example 1: Execute callback function when the observable completes
( StackBlitz )
Related Recipes
HTTP Polling
Additional Resources
finalize - Official docs
250
finalize / finally
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/finalize.ts
251
let
let
signature: let(function): Observable
Examples
Example 1: Reusing error handling logic with let
( jsBin | jsFiddle )
252
let
//faking request
const subscribe = Rx.Observable.of('some_url')
.mergeMap(url => examplePromise(url))
// could reuse error handling logic in multiple places with let
.let(retryThreeTimes)
//output: Complete: some_url
.subscribe(result => console.log(result));
//faking request
const secondSubscribe = Rx.Observable.of('some_url')
.mergeMap(url => examplePromise(url))
// could reuse error handling logic in multiple places with let
.let(customizableRetry(3))
//output: Complete: some_url
.subscribe(result => console.log(result));
( jsBin | jsFiddle )
253
let
( jsBin | jsFiddle )
254
let
( jsBin | jsFiddle )
Additional Resources
let - Official docs
255
let
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/let.ts
256
repeat
repeat
signature: repeat(count: number): Observable
Examples
Example 1: Repeat 3 times
( StackBlitz )
// RxJS v6+
import { repeat, delay } from 'rxjs/operators';
import { of } from 'rxjs';
delayedThing.pipe(
repeat(3)
)
.subscribe(console.log)
Additional Resources
repeat - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/repeat.ts
257
repeat
258
timeout
timeout
signature: timeout(due: number, scheduler: Scheduler):
Observable
Examples
Example 1: Timeout after 2.5 seconds
259
timeout
// RxJS v6+
import { of } from 'rxjs';
import { concatMap, timeout, catchError, delay } from 'rxjs/oper
ators';
// simulate request
function makeRequest(timeToDelay) {
return of('Request Complete!').pipe(delay(timeToDelay));
}
Additional Resources
timeout - Official Docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/timeout.ts
260
toPromise
toPromise
signature: toPromise() : Promise
Examples
Example 1: Basic Promise
( jsBin | jsFiddle )
( jsBin | jsFiddle )
261
toPromise
Additional Resources
toPromise - Official Docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/toPromise
.ts
262
Full Listing
263
Full Listing
filter
finalize / finally
first
forkJoin
from
fromEvent
groupBy
iif
ignoreElements
interval
last
let
map
mapTo
merge
mergeAll
mergeMap / flatMap
multicast
of
partition
pluck
publish
race
range
repeat
retry
retryWhen
sample
scan
sequenceequal
share
shareReplay
single
skip
skipUntil
skipWhile
264
Full Listing
startWith
switchMap
take
takeUntil
takeWhile
throttle
throttleTime
throw
timeout
timer
toArray
toPromise
window
windowCount
windowTime
windowToggle
windowWhen
withLatestFrom
zip
- commonly used
Additional Resources
What Are Operators? - Official Docs
What Operators Are - André Staltz
265
Subjects
Subjects
A Subject is a special type of Observable which shares a single execution path
among observers.
You can think of this as a single speaker talking at a microphone in a room full of
people. Their message (the subject) is being delivered to many (multicast) people
(the observers) at once. This is the basis of multicasting. Typical observables
would be comparable to a 1 on 1 conversation.
Contents
AsyncSubject
BehaviorSubject
ReplaySubject
Subject
Additional Resources
Official Overview
Official Documentation
On The Subject Of Subjects (in RxJS) - Ben Lesh
266
AsyncSubject
AsyncSubject
Examples
Example 1: simple AsyncSubject
( Stackblitz )
// RxJS v6+
import { AsyncSubject } from 'rxjs';
sub.subscribe(console.log);
sub.subscribe(console.log);
Additional Resources
AsyncSubject - Official docs
267
AsyncSubject
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/AsyncSubject.ts
268
BehaviorSubject
BehaviorSubject
Examples
Example 1: simple BehaviorSubject
( Stackblitz )
// RxJS v6+
import { BehaviorSubject } from 'rxjs';
//two new subscribers will get initial value => output: 123, 123
subject.subscribe(console.log);
subject.subscribe(console.log);
//two subscribers will get new value => output: 456, 456
subject.next(456);
//new subscriber will get latest value (456) => output: 456
subject.subscribe(console.log);
//all three subscribers will get new value => output: 789, 789,
789
subject.next(789);
269
BehaviorSubject
( Stackblitz )
// RxJS v6+
import { BehaviorSubject, fromEvent, interval, merge } from 'rxj
s';
import { map, tap, mergeMap } from 'rxjs/operators';
270
BehaviorSubject
merge(click$, interval$).subscribe();
Additional Resources
BehaviorSubject - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/BehaviorSubject.ts
271
ReplaySubject
ReplaySubject
Examples
Example 1: simple ReplaySubject
( Stackblitz )
// RxJS v6+
import { ReplaySubject } from 'rxjs';
sub.next(1);
sub.next(2);
sub.subscribe(console.log); // OUTPUT => 1,2
sub.next(3); // OUTPUT => 3
sub.next(4); // OUTPUT => 4
sub.subscribe(console.log); // OUTPUT => 2,3,4 (log of last 3 va
lues from new subscriber)
sub.next(5); // OUTPUT => 5,5 (log from both subscribers)
Additional Resources
ReplaySubject - Official docs
272
ReplaySubject
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/ReplaySubject.ts
273
Subject
Subject
Examples
Example 1: simple Subject
( Stackblitz )
// RxJS v6+
import { Subject } from 'rxjs';
sub.next(1);
sub.subscribe(console.log);
sub.next(2); // OUTPUT => 2
sub.subscribe(console.log);
sub.next(3); // OUTPUT => 3,3 (logged from both subscribers)
Additional Resources
Subject - Official docs
Source Code:
https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts
274
Subject
275
Recipes
Recipes
Common use-cases and interesting recipes to help learn RxJS.
Contents
Game Loop
Horizontal Scroll Indicator
HTTP Polling
Progress Bar
Smart Counter
Type Ahead
276
Game Loop
Game Loop
By @barryrowe
This recipe demonstrates one way you might create a Game Loop as a combined
set of streams. The recipe is intended to highlight how you might re-think existing
problems with a reactive approach. In this recipe we provide the overall loop as a
stream of frames and their deltaTimes since the previous frames. Combined with
this is a stream of user inputs, and the current gameState, which we can use to
update our objects, and render to to the screen on each frame emission.
Example Code
( StackBlitz )
const boundaries = {
left: 0,
top: 0,
bottom: 300,
right: 400
};
const bounceRateChanges = {
left: 1.1,
top: 1.2,
277
Game Loop
bottom: 1.3,
right: 1.4
}
const baseObjectVelocity = {
x: 30,
y: 40,
maxX: 250,
maxY: 200
};
/**
* This is our core game loop logic. We update our objects and g
ameState here
* each frame. The deltaTime passed in is in seconds, we are giv
ent our current state,
* and any inputStates. Returns the updated Game State
*/
const update = (deltaTime: number, state: any, inputState: any):
any => {
//console.log("Input State: ", inputState);
if(state['objects'] === undefined) {
state['objects'] = [
{
// Transformation Props
x: 10, y: 10, width: 20, height: 30,
// State Props
isPaused: false, toggleColor: '#FF0000', color: '#000000'
,
// Movement Props
velocity: baseObjectVelocity
},
{
// Transformation Props
x: 200, y: 249, width: 50, height: 20,
// State Props
isPaused: false, toggleColor: '#00FF00', color: '#0000FF'
,
// Movement Props
velocity: {x: -baseObjectVelocity.x, y: 2*baseObjectVelo
278
Game Loop
city.y} }
];
} else {
state['objects'].forEach((obj) => {
// Process Inputs
if (inputState['spacebar']) {
obj.isPaused = !obj.isPaused;
let newColor = obj.toggleColor;
obj.toggleColor = obj.color;
obj.color = newColor;
}
279
Game Loop
return state;
}
/**
* This is our rendering function. We take the given game state
and render the items
* based on their latest properties.
*/
const render = (state: any) => {
const ctx: CanvasRenderingContext2D = (<HTMLCanvasElement>game
Area).getContext('2d');
// Clear the canvas
ctx.clearRect(0, 0, gameArea.clientWidth, gameArea.clientHeight
);
state['objects'].forEach((obj) => {
ctx.fillStyle = obj.color;
ctx.fillRect(obj.x, obj.y, obj.width, obj.height);
});
};
/**
* This function returns an observable that will emit the next f
rame once the
* browser has returned an animation frame step. Given the previ
ous frame it calculates
* the delta time, and we also clamp it to 30FPS in case we get
long frames.
*/
const calculateStep: (prevFrame: IFrameData) => Observable<IFram
eData> = (prevFrame: IFrameData) => {
return Observable.create((observer) => {
requestAnimationFrame((frameStartTime) => {
// Millis to seconds
const deltaTime = prevFrame ? (frameStartTime - prevFrame.
frameStartTime)/1000 : 0;
observer.next({
280
Game Loop
frameStartTime,
deltaTime
});
})
})
.pipe(
map(clampTo30FPS)
)
};
281
Game Loop
keyMap[name] = event.code;
return keyMap;
} else {
return undefined;
}
}),
filter((keyMap) => keyMap !== undefined)
);
282
Game Loop
)
.subscribe((gameState) => {
render(gameState);
});
return 1/(total/frames.length);
})
).subscribe((avg) => {
fps.innerHTML = Math.round(avg) + '';
})
supporting js
game.util.ts
keys.util.ts
frame.interface.ts
html
283
Game Loop
Operators Used
buffer
bufferCount
expand
filter
fromEvent
map
share
tap
withLatestFrom
284
Horizontal Scroll Indicator
Example Code
( StackBlitz )
// RxJS v6+
import { fromEvent } from 'rxjs';
import { throttleTime, tap } from 'rxjs/operators';
fromEvent(document, 'scroll')
.pipe(
throttleTime(20),
tap(setScroll)
)
.subscribe()
285
Horizontal Scroll Indicator
html
<style>
#indication {
position: fixed;
width: 5px;
height: 7px;
background-color: #FF3366;
left: 0px;
right: 0px;
top: 0px;
z-index: 2;
}
</style>
<div id="indication"> </div>
Scroll down!!!
<div class="app" style="position: absolute; margin-top: 3000px;">
Boom!</div>
Operators Used
fromEvent
tap
throttleTime
286
Http Polling
HTTP Polling
Examples
Example 1
By @barryrowe
This recipe demonstrates one way you can achieve polling an HTTP endpoint on
an interval. This is a common task in web applications, and one that RxJS tends
to handle really well as the continuous series of HTTP requests and responses is
easy to reason about as a stream of data.
( StackBlitz )
// Import stylesheets
import './style.css';
287
Http Polling
};
reader.readAsDataURL(blob);
}));
}
/*************************
* Our Operating State
*************************/
// Which type of data we are requesting
let requestCategory: RequestCategory = 'cats';
// Current Polling Subscription
let pollingSub: Subscription;
/*************************/
/**
* This function will make an AJAX request to the given Url, map
the
* JSON parsed repsonse with the provided mapper function, and e
mit
* the result onto the returned observable.
*/
function requestData(url: string, mapFunc: (any) => Observable<s
tring>): Observable<string> {
console.log(url)
const xhr = new XMLHttpRequest();
return from(new Promise<string>((resolve, reject) => {
288
Http Polling
xhr.addEventListener("load", () => {
resolve(xhr.response);
});
xhr.open("GET", targetUrl);
if(requestCategory === 'cats') {
// Our cats urls return binary payloads
// so we need to respond as such.
xhr.responseType = "arraybuffer";
}
xhr.send();
}))
.pipe(
switchMap((data) => mapFunc(xhr.response)),
tap((data) => console.log('Request result: ', data))
);
}
/**
* This function will begin our polling for the given state, and
* on the provided interval (defaulting to 5 seconds)
*/
function startPolling(category: RequestCategory, interval: numbe
r = 5000): Observable<string> {
const url = category === 'cats' ? CATS_URL : MEATS_URL;
const mapper = category === 'cats' ? mapCats : mapMeats;
289
Http Polling
s'));
const meatsClick$ = fromEvent(meatsRadio, 'click').pipe(mapTo('m
eats'));
const catImage: HTMLImageElement = <HTMLImageElement>document.ge
tElementById('cat');
// Stop polling
let stopPolling$ = fromEvent(stopButton, 'click');
function updateDom(result) {
if (requestCategory === 'cats') {
catImage.src = result;
console.log(catImage);
} else {
text.innerHTML = result;
}
}
290
Http Polling
meatsClick$
.subscribe((category: RequestCategory) => {
requestCategory = category;
catImage.style.display = 'none';
text.style.display = 'block';
});
// Start Polling
fromEvent(startButton, 'click')
.pipe(
// for demo purposes only
tap(_ => pollingStatus.innerHTML = 'Started'),
mergeMap(_ => watchForData(requestCategory))
)
.subscribe();
Operators Used
filter
fromEvent
from
map
mapTo
merge
mergeMap
switchMap
timer
By @adamlubek
This recipe demonstrates polling an HTTP endpoint using repeat. It waits for 3
seconds following the response to poll again. Code below is simplifed to
demonstrate bare bones of solution but link below contains verbose logging and
error handling.
( StackBlitz )
291
Http Polling
// RxJS v6+
import { of } from 'rxjs';
import { delay, tap, mergeMap, repeat } from 'rxjs/operators';
poll.subscribe();
292
Progress Bar
Progress Bar
By @barryrowe
This recipe demonstrates the creation of an animated progress bar, simulating the
management of multiple requests, and updating overall progress as each
completes.
Example Code
( StackBlitz )
import './style.css';
293
Progress Bar
294
Progress Bar
clicks$.pipe(switchMapTo(ratio$)).subscribe(updateProgress);
progress$.subscribe(displayData);
html
<div class="progress-container">
<div class="progress" id="progress"></div>
</div>
<button id="load">
Load Data
</button>
<div id="data">
</div>
Operators Used
concatAll
delay
fromEvent
from
scan
share
switchMap
withLatestFrom
295
Smart Counter
Smart Counter
An interesting element on interfaces which involve dynamically updating numbers
is a smart counter, or odometer effect. Instead of jumping a number up and down,
quickly counting to the desired number can achieve a cool effect. An example of a
popular library that accomplishes this is odometer by Hubspot. Let's see how we
can accomplish something similar with just a few lines of RxJS.
Vanilla JS
( JSBin | JSFiddle )
296
Smart Counter
// utility functions
const takeUntilFunc = (endRange, currentNumber) => {
return endRange > currentNumber
? val => val <= endRange
: val => val >= endRange;
};
HTML
297
Smart Counter
We can easily take our vanilla smart counter and wrap it in any popular
component based UI library. Below is an example of an Angular smart counter
component which takes an Input of the updated end ranges and performs the
appropriate transition.
Angular Version
( StackBlitz )
@Component({
selector: 'number-tracker',
template: `
<h3> {{ currentNumber }}</h3>
`
})
export class NumberTrackerComponent implements OnDestroy {
@Input()
set end(endRange: number) {
this._counterSub$.next(endRange);
}
@Input() countInterval = 20;
public currentNumber = 0;
private _counterSub$ = new Subject();
private _onDestroy$ = new Subject();
constructor() {
this._counterSub$
.pipe(
switchMap(endRange => {
return timer(0, this.countInterval).pipe(
mapTo(this.positiveOrNegative(endRange, this.current
Number)),
startWith(this.currentNumber),
scan((acc: number, curr: number) => acc + curr),
takeWhile(this.isApproachingRange(endRange, this.cur
298
Smart Counter
rentNumber))
)
}),
takeUntil(this._onDestroy$)
)
.subscribe((val: number) => this.currentNumber = val);
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
}
}
HTML
<p>
<input type="number"
(keyup.enter)="counterNumber = vanillaInput.value"
#vanillaInput>
<button
(click)="counterNumber = vanillaInput.value">
Update number
</button>
</p>
<number-tracker [end]="counterNumber"></number-tracker>
Operators Used
299
Smart Counter
fromEvent
map
mapTo
scan
startWith
switchMap
takeWhile
300
Type Ahead
Type Ahead
By adamlubek
This recipe demonstrates the creation of type ahead client side code.
Example Code
( StackBlitz )
301
Type Ahead
// RxJS v6+
import { fromEvent, of } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, switchMap, tap
} from 'rxjs/operators';
fromEvent(document.getElementById('type-ahead'), 'keyup')
.pipe(
debounceTime(200),
map((e: any) => e.target.value),
distinctUntilChanged(),
switchMap(fakeContinentsRequest),
tap(c => document.getElementById('output').innerText = c.join
('\n'))
).subscribe();
html
Get continents
<input id='type-ahead'/>
<hr/>
<div id='output'></div>
Operators Used
302
Type Ahead
debounceTime
distinctUntilChanged
fromEvent
map
of
switchMap
tap
303
Concepts
Concepts
Short explanations of common RxJS scenarios and use-cases.
Contents
RxJS v5 -> v6 Upgrade
Understanding Operator Imports
304
RxJS v5 -> v6 Upgrade
RxJS-TsLint
TsLint rules for migration to RxJS 6. Auto-update project for new import paths and
transition to pipeable operators.
Pipeable Operators
Explanation and examples of utilizing pipeable operators.
305
Understanding Operator Imports
import 'rxjs/add/operator/take';
This adds the imported operator to the Observable prototype for use
throughout your project:
(Source)
Observable.prototype.take = take;
This method is generally OK for private projects and modules, the issue arises
when you are using these imports in say, an npm package or library to be
consumed throughout your organization.
A Quick Example
To see where a problem can spring up, let's imagine Person A is creating a public
Angular component library. In this library you need a few operators so you add the
typical imports:
some-public-library.ts
306
Understanding Operator Imports
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/switchMap';
Person B comes along and includes your library. They now have access to these
operators even though they did not personally import them. Probably not a huge
deal but it can be confusing. You use the library and operators, life goes on...
A month later Person A decides to update their library. They no longer need
switchMap or concatMap so they remove the imports:
some-public-library.ts
import 'rxjs/add/operator/take';
Person B upgrades the dependency, builds their project, which now fails. They
never included switchMap or concatMap themselves, it was just working
based on the inclusion of a 3rd party dependency. If you were not aware this could
be an issue it may take a bit to track down.
The Solution
Instead of importing operators like:
import 'rxjs/add/operator/take';
This keeps them off the Observable prototype and let's us call them directly:
307
Understanding Operator Imports
take.call(
of(1,2,3),
2
);
map.call(
take.call(
of(1,2,3),
2
),
val => val + 2
);
Pretty soon we have a block of code that is near impossible to understand. How
can we get the best of both worlds?
Pipeable Operators
RxJS now comes with a pipe helper on Observable that alleviates the pain
of not having operators on the prototype. We can take the ugly block of code from
above:
308
Understanding Operator Imports
map.call(
take.call(
of(1,2,3),
2
),
val => val + 2
);
of(1,2,3)
.pipe(
take(2),
map(val => val + 2)
);
Much easier to read, right? This also has the benefit of greatly reducing the RxJS
bundle size in your application. For more on this, check out Ashwin
Sureshkumar's excellent article Reduce Angular app bundle size using lettable
operators.
309