Reputation: 4536
I was wondering is there any difference between using a single myObservable.pipe(...) vs chaining myObservable.pipe(...).pipe(...).
Question is are those 2 examples identical? Is there a use case for pipe chaining?
Example with single pipe:
from([1, 2, 3])
.pipe(
delay(1000),
map((value: number) => value * 2),
map((value: number) => value * 3)
)
.subscribe((value) => {
console.log('result:', value);
});
Example with chaining pipes:
from([1, 2, 3])
.pipe(delay(1000))
.pipe(map((value: number) => value * 2))
.pipe(map((value: number) => value * 3))
.subscribe((value) => {
console.log('result:', value);
});
Upvotes: 5
Views: 1787
Reputation: 2663
RxJS is known for its operators. Essentially there is a kind of operators that take an observable as input and return another observabl, these are pipeable operators for example filter, map etc.
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified.
Now, the pipe operator just gives us syntax flexibility, to combine operators (logically thinking they are inside a pipe, where one would be run after the other).
Theoretically it doesn't make a difference that you chain pipe operators, but the sole purpose of pipe operator is to combine multiple operators, so its a good practice to combine group of operators inside a single pipe.
Upvotes: 1
Reputation: 13071
No, there isn't. However, I would like to help you understand why:
This code:
from([1,2,3]).pipe(
delay(1000)
)
is 100% equivalent to:
delay(1000)(
from([1, 2, 3])
)
And this code:
from([1, 2, 3])
.pipe(
delay(1000),
map((value: number) => value * 2),
)
is the same as:
map((value: number) => value * 2)(
delay(1000)(
from([1, 2, 3])
)
)
Etc, etc.
The thing is that piepable operators (the ones that you can use inside pipe) are "Observable
enhancers" (a type of higher order functions). What those functions return is a function that will enhance the Observable
that has received as an argument and it will return a new Observable
with some "enahnced" behavior.
Therefore, pipe
is just sugar for composing those Observable
enhancers in a more declarative manner.
For instance, a basic implementation of the map
piepable operator would look like this:
const map = <I, O>(mapper: (input: I) => O) =>
(source$: Observable<I>): Observable<O> =>
new Observable<O>(observer => source$.subscribe({
next: (value) => {
observer.next(mapper(value));
},
error: (e) => {
observer.error(e);
},
complete: () => {
observer.complete();
}
}))
Upvotes: 3