observable which is made based on another hot observable is definitely hot? - rxjs

Is this true? I'm currently a little confused:
observable which is made(merge, scan, map, filter... ) based on another hot observable is definitely hot?
Whatif I merged hot and cold observable together? is the new observable hot or cold?
Edit: test, result not expected
var source = Rx.Observable.fromEvent(window, 'mousemove')
.merge(Rx.Observable.from([1,2,3,4,5]))
.scan(acc=>++acc, 0);
setTimeout(()=>{
source.subscribe(x=>{
console.log('sub1', x)
})
}, 4000)
setTimeout(()=>{
source.subscribe(x=>{
console.log('------sub2', x)
})
}, 6000)
As paulpdaniels mentioned in his answer, mousemove should be a hot observable, so it should emit values even if there's no subscription.
But in the code example above, I delayed the subscription for 4 and 6 seconds. So when the application starts, I move my mouse around. When it reaches the 4th second, it logs out:
"sub1" 1
"sub1" 2
"sub1" 3
"sub1" 4
"sub1" 5
why it starts from 1?? doesn't it should have been accumulating values for 4 seconds? it should start from a bigger number from my understanding.
When it reaches the 6th second, it logs out:
"------sub2" 1
"------sub2" 2
"------sub2" 3
"------sub2" 4
"------sub2" 5
Why? doesn't it mean mousemove is cold observable?? or the problem is on scan operator??
PS: I'm using rxjs 5

That is correct. Hot simply means that it can produce events in the absence of subscribers. So if a source is hot then regardless of what comes after it, that source will remain hot.
Consider a simple example of a mouse event handler.
var mousemove = Rx.Observable.fromEvent(window, 'mousemove');
No matter what operators you attach to it, the source (mouse event handler) will produce a new event for every mouse movement. If there are no listeners attached, then none of those events will get processed and none of the logic after mousemove does anything, but those events will still be dutifully created and then silently forgotten.
There are some exceptions where a hot Observable can be made to appear like a cold Observable say by using replay, but that is simply buffering events for future subscribers, not changing the nature of the source.
As to your question regarding merging hot and cold. Since one of the sources is hot then the combined source would also be considered hot, because again it would continue to produce events regardless of the presence of subscribers. i.e.
//Still hot because the mouse does not stop generating events in the
//absence of subscribers.
var source = Rx.Observable.fromEvent(window, 'mousemove')
.merge(Rx.Observable.from([1,2,3,4,5]));

Related

Do RxJS observers always process all events submitted before the observable is completed?

I want to make sure that all events, which were submitted before complete was invoked on the observable, are logged.
I'm aware that operators exist that stop emission of events (takeUntil, etc.) completely.
The question that I have is whether other operators exist which would lead to emissions not being sent if the complete on the subject is sent too 'early'. Are there cases where it would be beneficial to wait with the completion of the observable until the event was handled by the observer?
For example, are there situations (imagine any other RxJS operator instead of the delay) where the following code ...
const subj = new Subject<string>();
subj.pipe(delay(500))
.subscribe((val) => {
console.log(val);
subj.complete();
});
subj.next('1');
... makes more sense than that ...
const subj = new Subject<string>();
subj.pipe(delay(500))
.subscribe((val) => {
console.log(val);
});
subj.next('1');
subj.complete();
... when the subject should only emit one value?
Or is completing the subject immediately after next always safe in such situations?
If there are other factors I'm not aware of (e.g. synchronous vs. asynchronous execution of code) please mention them as well.
In general,
subj.next('1');
subj.complete();
is safe. As far as I know, none of the existing RxJS operators use a completion to cancel/unsubscribe observables early.
That being said, I can easily create such an operator myself. switchMap will cancel currently running inner observables when it receives it's next emission. You could, for example, create a custom operator that unsubscribes and exists early when it receives a complete event.
If your worried about that, however, you're out of luck. No matter what workaround you imagine, I can probably write an operator that will ruin your code. For example filter(_ => false) will stop the 1 from being emitted before the complete in either of the two cases you've described.
In the end, you and your coworkers must write good code (and test!) and RxJS doesn't change that.

RxJs Window : not getting last observable

I've written this piece of code,
timer(0, 100)
.pipe(
windowTime(1000),
take(3),
flatMap( value => value.pipe(toArray())))
I don't understand why in my subscribe I only get 2 values. Whatever n take I always get n-1 values in my subscribe.
Could you explain to me why ?
Edit: I suspect a bug therefore I opened a bug.
Interesting problem!
So, windowTime(1000) will emit a new window every 1000ms. But what exactly is a window? A window is Subject instance.
windowTime can manage multiple windows, but when you're only providing its first argument(called windowTimeSpan), there will be only one active window. What this means is that after windowTimeSpan ms pass, the current window will be closed and a new one will be created and pushed into the stream.
When a window is closed, it means that it will send a complete notification. This is a very important aspect.
When you subscribe, a window is going to be created immediately and pushed into the stream.
By doing flatMap(value => value.pipe(toArray()))), you can register observers for the current window(subject). It's semantically the same as subject.pipe(toArray()).subscribe(subscriber)
Why does it behave this way?
timer(0, 100)
.pipe(
// Emit a value(window) every 1000ms and close(complete) the prev one
windowTime(1000),
take(3),
flatMap( value => value.pipe(toArray()))
)
Firstly, let's have a look at flatMap. flatMap is the same as mergeMap. What mergeMap does is to manage a number(concurrent, defaults to INFINITY) of inner observables. An inner observable is being tracked until it completes.
What toArray does it to accumulate values until its source completes. In this case, until the current subject(window) completes. This happens when a window is closed, more specifically, when 1000ms pass.
So, as delineated before, a window will be created immediately on subscription.
After 0ms a value(0) comes in, after 100ms another value(1) and so forth until value 9 comes in. In the meanwhile all these values were collected by toArray. So 9's arrival also marks 1000ms, that is also when the current window will be closed(will emit a complete notification). When this happens, toArray will receive the notification and will send the collected values to the data consumer.
After this a new window is created(second value for take(3)). Then, value 10 comes in, then value 11 and so forth until 19, which marks another 1000ms, which will cause the current window to complete and a new one to be created. But this new window would represent the 3rd value for take(3). This means that take will unsubscribe from its source and will emit a complete notification.
As a result, the source will not be able to receive any other values, so this should explain why you're only getting 2 arrays.

Share operator that doesn't unsubscribe

I need to lazy load some infinite streams because they are expensive to start. And I also don't ever want to stop them once they are started for the same reason.
I'm thinking it would be neat if there was a share operator that didn't unsubscribe from the underlying stream ever once it is subscribed for the first time, even when all downstream subscribers unsubscribe.
Right now I'm doing it with a publish and a connect on two different lines, which works alright but just seems clunky and not very rxjs like:
public data$(): Observable<any> {
if (this.lazyData$) {
return this.lazyData$;
}
this.lazyData$ = this.someDataProvider.data$()
.publishReplay(1);
this.lazyData$.connect();
return this.lazyData$;
}
Also I want it to replay the last message to new subscribers as you see :)
The shareReplay operator was added in RxJS version 5.4.0. And, in version 5.5.0 a bug was fixed so that it maintains its history when its subscriber count drops to zero.
With the fix, shareReplay will effect the behaviour you are looking for, as it will now unsubscribe from the source only when the source completes or errors. When the number of subscribers to the shared observable drops to zero, the shared observable will remain subscribed to the source.
The behaviour of shareReplay has changed several times and a summary of the changes - and the reasons for them - can be found in this blog post.
As of RxJS 6.4.0, you can specify shareReplay refCount behavior.
source.pipe(
shareReplay({ bufferSize: 1, refCount: true })
)
shareReplay will unsubscribe from source after all subscribers have unsubscribed.

RxJS - pausing an Observable until second Observable completes,

I have a scenario where 1 observable listens for events, which should then fire another asynchrounous event, and wait before it runs the next item in the source Observable.
The first observable can be triggered much faster than the the async event, and it must wait for the async event to complete before it takes another item from the 1st observable.
So.. essentially I need to set up a 'queue' from the first observable (as I cant lose the data from source 1)
Source 2 should take 1 item at a time from the queue, run it, remove the item from the queue, and go onto the next item in the queue .
src1- --ev1---ev2---ev3----ev4---ev5--ev6---
src2- --ev1------------ev2-------------ev3--------ev4-------ev5------ev6
--------------async-----------async---------async------async------asyc
I was looking at the RX docs and it seems that pausibleBuffered could be a solution but I noticed it has been removed in RX5, which is what I am using. Can someone give advice as the right way to accomplish this ?
Thanks!
You can use mergeScan to run async operations one by one because it needs the previous async operation’s result to run an async operation.
const src2 = src1.mergeScan((_, value) => doSomething(value));
http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-mergeScan

RxJS Sample - Why last event from the source is not emitted

From RxJS documentation for sample operator (Rxjs-sample), it says:
Whenever the notifier Observable emits a value or completes, sample looks at the source Observable and emits whichever value it has most recently emitted since the previous sampling, unless the source has not emitted anything since the previous sampling.
However, the following code does not seem to behave appropriately:
Rx.Observable.zip(
Rx.Observable.from(['Joe', 'Frank', 'Bob']),
Rx.Observable.interval(2000)
)
.sample(Rx.Observable.interval(2500))
.subscribe(console.log);
The output is as follows:
[ 'Joe', 0 ]
[ 'Frank', 1 ]
Why does the output not include ['Bob', 2]?
It is the expected behavior. The notifier Observable does not complete when the source Observable completes. It's free to complete whenever; before or after the source Observable. This snippet of the documentation:
Whenever the notifier Observable ... completes
is only referring to the case where the notifier Observable completes before the source Observable. Your notifier Observable:
Rx.Observable.interval(2500)
never completes, so only the values that are emitted while the source Observable is still alive will be taken into account. To draw a rough marble diagram:
Source: -----O-----O-----O|
Notifier: ------O------O------O--...
Only the first two marbles on the notifier Observable will cause sample to emit values. When the source Observable dies, the whole chain is dead and the notifier Observable no longer matters. In fact, I'd bet Rxjs is smart enough to unsubscribe from it so as to not cause a memory leak.

Resources