I tried to google it, but I cannot find any clear answer for that.
From the documentation, I noticed that one is operator, and one is function.
What is the difference between them? and what should I use in my code?
Thanks!
Here is the documentation link:
https://rxjs-dev.firebaseapp.com/api/operators/timeInterval
https://rxjs-dev.firebaseapp.com/api/index/function/interval
interval() is a so called Observable creation method that returns an Observable that emits periodically an ever increasing sequence of numbers with a constant delay between them.
timeInterval() is an operator that basically "timestamps" each emission from its source with time between the two most recent emissions.
The main and probably more obvious difference is how you use them:
range(1, 20).pipe(
timeInterval(), // `timeInterval()` is an operator
).subscribe(...); // TimeInterval objects
interval(1000).pipe( // `interval()` is a source Observable
).subscribe(...); // 0, 1, 2, ...
Related
of([1,2,3]).subscribe(console.log)
prints:[1,2,3]
But:
of([1,2,3]).pipe(concatAll()).subscribe(console.log)
prints:
1
2
3
Why the above happens? Why adding concatAll() emits the elements of the array one by one? Isn't this somehow the opposite of what the word concat means?
I feel that concatAll() acts differently depending on the input.
Consider also this:
from([of(1),of(2),of(3)]).pipe(concatAll()).subscribe(console.log)
It will again print:
1
2
3
So of([1,2,3]).pipe(concatAll()) == from([of(1),of(2),of(3)]).pipe(concatAll())
But of([1,2,3]) != from([of(1),of(2),of(3)]) because subscribing to the latter will print:
Observable { _isScalar: false, _subscribe: [Function] }
Observable { _isScalar: false, _subscribe: [Function] }
Observable { _isScalar: false, _subscribe: [Function] }
The right side of the above equality is pretty clear to me, but where is documented that concatAll() should emit all the values of the array separately, acting like a pipeable from?
All the operators that deal with higher-order observable operators, perform the same conversion that RxJS's from operator does.
that is:
mergeMap(_ => ([1,2,3]))
Is basically the same as
mergeMap(_ => from([1,2,3]))
That works the same when merging/switching/concatenating promises and other iterables.
The difference you're seeing in behaviour is also attributed to the fact that from creates a new observable, while the higher-order observable operators tend to create a new observables and define behaviour around how those observables are subscribed to.
so concatAll is adding extra behaviour.
Finally, just because two things have similar outputs for a given example, doesn't mean they're doing the same thing under the hood.
of([1,2,3]).pipe(concatAll()) and from([of(1),of(2),of(3)]).pipe(concatAll()) describe two very different set of behaviours that in (this case) give you the same output to the console.
The first emits an array and has that array turned into a stream of numbers by concatAll(). The second emits three observables, and has has concatAll() subscribe to each only when the previous one completes. They complete after emitting just one number.
You can see the distinction clearly with your second example:
of([1,2,3]) and from([of(1),of(2),of(3)])
The first emits and array, the second emits three observables. That hasn't changed.
concat([1,2,3]), &&
concat(of(1), of(2), of(3))
Emit the same output again as well.
As title suggest, both function seems to have similar effect and return emit nothing when predicate does not match. It looks like skipWhile is the reverse of filter ?
As #cartant says
skipWhile "... emits all further source items as soon as the condition becomes false"
Note that skipWhile takes a predicate (expression that returns a boolean).
In addition there is also skipUntil, which this takes an observable and values will be skipped until that observable emits anything.
So sometimes the following can be useful (pan is a hammerjs event btw.):
// When event.deltaX reaches 20 emit true to indicate a threshold is reached
const thresholdReached$ = pan$.pipe(map(e => Math.abs(e.deltaX) > 20 ), first(v => v), shareReplay(1));
// Emit all events, but skip them until the first time that thresholdReached$ emits
const panMove$ = pan$.pipe(skipUntil(thresholdReached$));
Important to realize that the observable passed to skipUntil can emit any value to trigger the skipping to stop. It doesn't have to be a 'truthy' value.
So if you have var b = new BehaviorSubject(false) then skipUntil(b) will immediately stop skipping and you will quickly get very confused!
According to the documentation, the buffer transform will wait for a delay before emitting any values. What I'd like is to get the current value immediately, then only update every X seconds.
I've not been able to achieve this with rxjs yet. The closest I've come is to bind the observable then use a setTimeout function to rebind after the buffer timeout occurs. This has a side effect of clearing the current value for those X seconds before emitting the current values.
Any ideas?
Thanks!
Assuming by "current value immediately" you mean "first value as soon as it emits", you can buffer on the second element to the last, and merge in the first:
// source$: Observable<T>
const pub_source$ = source$.publish();
Observable.merge(
pub_source$.take(1).map(first => [first]),
pub_source$.skip(1).buffer(Observable.interval(X))
);
pub_source$.connect();
The source needs to be cold so that take(1) and skip(1) relate to the same element, so we use publish. The first element is also wrapped to keep the output type T[] consistent.
There's an easier way using the zip operator, see lightbulb note in learnrxjs
Combined with interval or timer, zip can be used to time output from another source!
// Useful for slow source that emits at around the same rate as interval
// but suffers back-pressure with fast-emitting source
const interval = 1000
const output = Observable.zip(source, Observable.timer(0, interval))
.map(x => x[0])
The Observable.timer 'regulates' the output from source. Note, timer's first parameter sets the delay for the first emit.
Working example: CodePen
Footnote
I just realized this will create back-pressure (build-up of un-emitted values) if you have a lot of events per second, so buffer is the better way to go with a fast emitting source.
// Buffered version for fast source
const output2 = source.buffer(Observable.timer(0, interval))
.filter(x => x.length) // filter out empty buffer emits
.flatMap(x => Observable.from(x)) // optional, converts array back to single emits
Having such a convenient method like .startWith it would make sense to have his oposite, .endWith, which makes the observable yield a value whenever it gets completed.
I have come up with this solution, but is there anything better? This thing gets a bit hard to read for what it is.
source.concat(Rx.Observable.just(lastValue))
There is in RxJS6 (no clue when it was added to be honest)
Documentation:
https://rxjs-dev.firebaseapp.com/api/operators/endWith
Source: https://github.com/ReactiveX/rxjs/blob/df0ea7c78767c07a6ed839608af5a7bb4cefbde5/src/internal/operators/endWith.ts
Also, defaultIfEmpty() only emits a value if the observable CLOSES without emitting a value. It's a subtle, yet not so subtle distinction. It may have the same effect as endWith() in limited situations.
Example of endWith():
const source = of(1, 2, 3, 4, 5);
const example = source.pipe(
takeWhile(val => val != 4),
endWith(4));
Emits:
[1, 2, 3, 4]
Also I'm noticing that the https://learnrxjs.io website is increasingly out of date, and currently doesn't show this operator.
Why did I need it?
I was looking for the ability to emit false until a condition became true, but never go back to false. So slightly similar to debouncing, but not quite.
In rxjs5 doc, it mentions 'To reduce polymorphism and get better performance out of operators, some operators have been split into more than one operator'. What does it actually mean and how to use the mergeMapTo operator?
From the docs, mergeMapTo:
It's like mergeMap, but maps each value always to the same inner Observable.
I see mergeMapTo as a shortcut to always output the same value. mergeMapTo doesn't care about the source value.
Also from the docs:
Maps each source value to the given Observable innerObservable
regardless of the source value, and then merges those resulting
Observables into one single Observable, which is the output
Observable.
You'll see that mergeMap takes a function while mergeMapTo takes a value:
An example with mergeMap (we're transforming values):
Rx.Observable.of(1, 2, 3).mergeMap(x =>
Rx.Observable.interval(1000).map(i => x+i)
);
While using mergeMapTo we can take values from a stream and always output the same value (also transforming, but always to the same value):
Rx.Observable.of(1, 2, 3).mergeMapTo(10);