简体   繁体   中英

Observable wait for a method to complete

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...

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...

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.

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(); 

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

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM