With operators, we can do more with Rxjs observables. They’re useful for doing complex operations with asynchronous code.
Operators are functions. There’re 2 types of operators:
- Pipeable operators — they can be piped to Observables using the
pipe
method available in Observables. They return a new Observable, so multiple pipeable operators can be chained together - Creation operators — these are standalone functions to create a new Observable. For example,
of(1,2,3)
will emit 1, 2, and 3.
Using Operators
We can import operators from Rxjs to use to manipulate our observable results.
For example, we can map values from Observables to another using the map
function:
import { of } from "rxjs";
import { map } from "rxjs/operators";
map(x => x * 2)(of(1, 2, 3)).subscribe(val => console.log(val));
We created an Observable that emits 1, 2 and 3 with the of
function and then called map
with a callback to let us map the values, which returns a function where we can pass in the Observable that we created and returns a new Observable.
map(x => x * 2)(of(1, 2, 3))
returns a new Observable that we can subscribe to. Then we get the values 2, 4, and 6 in the subscribe
‘s callback function.
Piping
We can use the Observable’s pipe
method to compose multiple operations into one.
It takes multiple operations as arguments, which is much cleaner than nesting them.
For example, we can use it to rewrite the example we had above:
import { of, pipe } from "rxjs";
import { map } from "rxjs/operators";
of(1, 2, 3)
.pipe(map(x => x * 2))
.subscribe(val => console.log(val));
We get the same result, but it’s much cleaner.
Also, we can pass in more than one operation to the pipe
method:
of(1, 2, 3)
.pipe(
map(x => x * 2),
map(x => x * 3)
)
.subscribe(val => console.log(val));
Then we first multiply each value emitted by the Observable by 2, then we multiply the returned value again by 3. As a result, we get back 6, 12, and 18 in the console.log
.
Creation Operators
Creation operators are functions to create an Observable from scratch or by joining other Observables together.
For example, we have the interval
function to emit a value from 0 and up in the interval that we specify:
import { interval } from "rxjs";
interval(5000).subscribe(val => console.log(val));
The code above will output an integer from 0 and up every 5 seconds.
Higher-Order Observables
Higher-Order Observables are Observables of Observables. There’re a few things that we can do with different observables.
Rxjs has the concatAll()
operator that subscribes to each inner observable and copies all the emitted values until the outer observable completes.
For example, we can use it as follows:
import { of, pipe } from "rxjs";
import { concatAll, map } from "rxjs/operators";
of(1, 2, 3)
.pipe(
map(outerVal => {
console.log(`outerVal ${outerVal}`);
return of(4, 5, 6);
}),
concatAll()
)
.subscribe(innerVal => console.log(`innerVal ${innerVal}`));
We should get the output:
outerVal 1
innerVal 4
innerVal 5
innerVal 6
outerVal 2
innerVal 4
innerVal 5
innerVal 6
outerVal 3
innerVal 4
innerVal 5
innerVal 6
As we can see, we get the first value from the of(1,2,3)
Observable first, and then all the values from the second. Then we get the second value from of(1,2,3)
and then all the values from the second and so on.
Other operator functions include:
mergeAll()
— subscribes to each inner Observable as it arrives, and emits each value as it arrives.switchAll()
— subscribes to the first inner Observable when it arrives, then emits each value as it arrives. It unsubscribes to the previous one then subscribes to the new one.exhaust()
— subscribes to the first inner Observable when it arrives, then emits each value as it arrives, discarding all newly arriving Observables as it completes and waits for the next inner Observable.
They all give the same result as concatAll()
but the difference is underneath.
We can create new Observables by composing multiple Observables or operators.
For example:
of(1, 2, 3)
.pipe(
map(x => x * 2),
map(x => x * 3)
)
is an Observable that multiplies each value from Observableof(1, 2, 3)
by 6.
With Rxjs, there’re are built-in operators that we can use to create and manipulate Observable values. Also, we can create new Observables and combine them together in different ways.
Observables can also be nested, and the values of all the nested Observables can be obtained by using concatAll()
, mergeAll()
, switchAll()
or exhaust()
.