RxJS version: 5.0.0-beta.10
Code to reproduce:
/* Have staggering intervals */
var source1 = Rx.Observable.interval(100)
.map(function (i) { return 'First: ' + i; });
var source2 = Rx.Observable.interval(150)
.map(function (i) { return 'Second: ' + i; });
// Combine latest of source1 and source2 whenever either gives a value
var source = Rx.Observable.combineLatest(
source1,
source2
).take(4);
var subscription = source.subscribe(
function (x) {
console.log('Next: %s', JSON.stringify(x));
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
Expected behavior:
["First: 0","Second: 0"]
["First: 1","Second: 0"]
["First: 1","Second: 1"]
["First: 2","Second: 1"]
Completed
Actual behavior:
["First: 0","Second: 0"]
["First: 1","Second: 0"]
["First: 2","Second: 0"]
["First: 2","Second: 1"]
Completed
Additional information:
This code, just past from the doc
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/combinelatest.md
Here is a jsbin to reproduce : http://jsbin.com/xefowikiwo/edit?html,js,console
Thanks for the report.
I _think_ this happens because of the different default scheduler in RxJS v5, which isn't backwards compatible with the default scheduler in v4.
It's easy to see how RxJS v5 handles events that "happen at the same time" (2 from First, 1 from Second), it handles them by the order of subscription. source1 was subscribed first because the arguments to combineLatest were given as combineLatest(source1, source2).
If you swap them around as combineLatest(source2, source1), you see
["Second: 0","First: 0"]
["Second: 0","First: 1"]
["Second: 1","First: 1"]
["Second: 1","First: 2"]
which matches your expected behavior.
There are multiple other cases where RxJS v5 is not backwards compatible with v4 due to the default scheduler. I think this is just one more. And my guess is that it would remain like this.
We have to document these scheduling incompatibilities on the migration guide. I was supposed to do that, but I didn't have time to work on it yet.
Got it!
Thanks ;)
100ms
source1: 0, source2: ?, source: ?
150ms
source1: 0, source2: 0, source: 0,0
200ms
source1: 1, source2: 0, source: 1,0
300ms
source1: 2, source2: 0, source: 2,0 (rx5)
source1: 1, source2: 1, source: 1,1 (<5)
300ms (again : http://staltz.com/rx-glitches-arent-actually-a-problem.html)
source1: 2, source2: 1, source: 2,1
@t8g @staltz from what I can tell, this is a side-effect of using setInterval instead of setTimeout to schedule time-delayed asynchronous tasks. We use setInterval because the JS environment will attempt to invoke the callback closer to the period time than serially scheduling via setTimeout.
Here's an example of what's going on in plain JS:
let x1 = 0, x2 = 0, t1 = 100, t2 = 150;
const i1 = setInterval(() => {
console.log(`first @ ${++x1 * t1}`);
}, t1);
const i2 = setInterval(() => {
console.log(`second @ ${++x2 * t2}`);
}, t2);
const i3 = setInterval(() => {
clearInterval(i1);
clearInterval(i2);
clearInterval(i3);
}, t2 * 4);
/* prints:
first @ 100
second @ 150
first @ 200
first @ 300
second @ 300
first @ 400
second @ 450
first @ 500
first @ 600
second @ 600
*/
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Thanks for the report.
I _think_ this happens because of the different default scheduler in RxJS v5, which isn't backwards compatible with the default scheduler in v4.
It's easy to see how RxJS v5 handles events that "happen at the same time" (2 from First, 1 from Second), it handles them by the order of subscription.
source1was subscribed first because the arguments to combineLatest were given ascombineLatest(source1, source2).If you swap them around as
combineLatest(source2, source1), you seewhich matches your expected behavior.
There are multiple other cases where RxJS v5 is not backwards compatible with v4 due to the default scheduler. I think this is just one more. And my guess is that it would remain like this.