The standard way of doing this is indeed the merge function, which can receive any number of observables as arguments, and emits all of their items in sequece regardless of the order of the observables in the function parameters. But as you pointed out, it appended the results, the reason for this is not an issue with merge, but actually that of emmited the values synchronously, so they all ran in order in the same javascript loop. You can change that by using an observable that emits values assynchronously, or create an observable with some of the available async Schedulers
Assynchronous observable:
I created this asyncOffunction as a mockup to a Observable with values emmited over time, like a websocket client or user interations.
import { merge, Observable, EMPTY } from 'rxjs';
import { toArray } from 'rxjs/operators';
const asyncOf = <T = any>(args: T[], interval = 500): Observable<T> => {
let i = 0;
let intervalRef;
if(!args?.length) {
return EMPTY;
}
return new Observable(observer => {
intervalRef = setInterval(() => {
if(args[i]) {
observer.next(args[i])
}
++i;
if(!args[i]) {
observer.complete()
if(intervalRef) {
clearInterval(intervalRef)
}
}
}, interval)
})
}
const source1 = asyncOf([1, 3, 5, 7, 9]);
const source2 = asyncOf([2, 4, 6, 8, 10]);
//output: 1,2,3,4,5,6,7,8,9,10
const subscribe = merge(source1, source2)
//.pipe(toArray()) //collect all emmited values and emmit an array when the observable completes
.subscribe((val) => console.log(val));
In this case the merge works correctly, because both observables are running asynchronously.
Async schedulers
Another option is using one of the async schedulers (or create your own) to describe when each item should be emmited. This is closer to your example, and a somewhat deeper dive into rxjs:
import { merge, scheduled, asyncScheduler } from 'rxjs';
import { toArray } from 'rxjs/operators';
const source1 = scheduled([1, 3, 5, 7, 9], asyncScheduler);
const source2 = scheduled([2, 4, 6, 8, 10], asyncScheduler);
//output: 1,2,3,4,5,6,7,8,9,10
const subscribe = merge(source1, source2)
//.pipe(toArray()) //collect all emmited values and emmit an array when the observable completes
.subscribe((val) => console.log(val));
Scheduled comes on RXJS 6.5+ and deprecates the use of scheduler function in other functions like of,