Reputation: 1675
I want to run method A and B parallelly and once they both are done, I want to run method C.
How can I achieve this in javascript using Observable?
main() {
this.methodA();
if(some_condition) this.methodB();
this.methodC();
}
methodA() {
setTimeout( () => { console.log("doing some work A"); }, 500);
}
methodB() {
setTimeout( () => { console.log("doing some work B"); }, 250);
}
methodC() {
console.log("should be the last...");
}
expected output (if some_condition is false):
doing some work A
should be the last...
expected output (if some_condition is true):
doing some work A
doing some work B
should be the last...
expected output (if some_condition is true):
doing some work B
doing some work A
should be the last...
Upvotes: 0
Views: 1937
Reputation: 1053
As @CozyAzure said, Observable.if()
is what you want. Make sure to make use of Observable.merge()
and Observable.concat()
.
const methodA = () => Observable.timer(500).mapTo("doing some work A")
const methodB = () => Observable.timer(250).mapTo("doing some work B")
const methodC = () => Observable.of("should be the last...")
const main = (some_condition) =>
Observable.if(
() => some_condition,
methodA().merge(methodB()),
methodA()
)
.concat(methodC())
.subscribe(console.log)
main(true)
Here's the example in jsfiddle
If you're working with promises, you may want to defer the creation of your promise. For example,
const methodA = () => Observable.timer(500).mapTo("doing some work A")
const methodB = () => Observable.timer(250).mapTo("doing some work B")
const methodC = () => Promise.resolve("should be the last...")
Observable.merge(methodA(), methodB())
.concat(Observable.defer(() => methodC())
.subscribe(console.log)
Upvotes: 1
Reputation: 8478
People may forget the hidden gem of Observable.if()
.
Observable.if(condition, thenSource, [elseSource])
takes in 3 arguments. First argument is the boolean condition, second argument is an Observable to be emitted if condition is true, and the last one being an array of else source, that is to be emmitted if condition is false.
If you want to fully Observable-lised your code, you can do it this way:
1. Have all your methods return an Observable
:
const methodA = () => {
return Observable
.timer(500)
.do(() => {
//do your work A here
console.log('doing some work A');
})
};
const methodB = () => {
return Observable
.timer(250)
.do(() => {
//do your work B here
console.log('doing some work B');
})
};
const methodC = () => {
console.log("should be the last...");
};
2. Use Observable.if()
to resolve the streams
Now, in your main, simply use an Observable.if() to check if the condition is true, and emit the Observable accordingly:
const main = () => {
let some_condition = true;
Observable
.if(
//a function that returns true or false
() => some_condition,
//Observable to emitif condition is true
methodA().switchMap(() => methodB()),
//Observable to emit if condition is false
methodA()
)
.subscribe(() => {}, error => {}, methodC)
};
Here is the working JSBin for you.
More on Observable.if(): https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/if.md
Upvotes: 1
Reputation: 4676
While I agree that it seems like your spec could probably best be accomplished using promises, I figured I'd give you an answer using Observables, seeing how that's what you asked for.
Essentially, just use the merge
operator, make methodA()
and methodB()
return observables, and call methodC()
when they're all complete:
var some_condition = true
function main() {
let test$ = a()
if (some_condition) test$ = test$.merge(b())
test$.subscribe(console.log, null, c)
}
function a() {
return Rx.Observable.timer(500)
.mapTo('doing some work A')
}
function b() {
return Rx.Observable.timer(250)
.mapTo('doing some work B')
}
function c() {
console.log('should be the last...')
}
main()
This logs:
doing some work B
doing some work A
should be the last...
Upvotes: 2
Reputation: 138267
Use ES7s async functions / await :
async function main() {
await this.methodA();
if(true || some_condition) await this.methodB();
await this.methodC();
}
async function methodA() {
console.log("doing some work A");
await timer(1000);
console.log("finished A");
}
async function methodB() {
console.log("doing some work B");
await timer(1000);
console.log("finished B");
}
async function methodC() {
console.log("should be the last...");
}
function timer(time){
return new Promise(function(res){
setTimeout(res,time);
});
}
main();
Upvotes: 1
Reputation: 469
Your best bet would be to use a Promise which allow functions to be run asynchronously and then trigger some function when they have completed. The benefit here is that promises can be composed so that you can wait on any or all of them to resolve before doing some work.
Upvotes: 1