Rxjs toPromise behavior different than observable

2019-02-22 08:28发布

问题:

I have a simple example where two methods create and return a promise. The second method buildRedCar() calls the first method buildCar(), modifies the value returned by the promise and returns another promise from itself. The code then calls buildRedCar(), and just console.logs the result out. This does not work when converting to promises, but it does work when using straight observables.

Does not work:

import * as Rx from 'rx';

function buildCar(): Rx.IPromise<string> {
    let car = 'Car';
    return Rx.Observable.just<string>(car).toPromise();
}

function buildRedCar(): Rx.IPromise<string> {
    let observable = Rx.Observable.create<string>((observer) => {
        buildCar().then((car) => {
            observer.onNext('Red ' + car);
        });
    })

    return observable.toPromise();
}

buildRedCar().then((car) => {
    console.log(car);
});

Does work:

import * as Rx from 'rx';

function buildCar(): Rx.Observable<string> {
    let car = 'Car';
    return Rx.Observable.just<string>(car);
}

function buildRedCar(): Rx.Observable<string> {
    let observable = Rx.Observable.create<string>((observer) => {
        buildCar().subscribe((car) => {
            observer.onNext('Red ' + car);
        });
    })

    return observable;
}

buildRedCar().subscribe((car) => {
    console.log(car);
});

Any idea why the different behavior when the only difference is converting the observable to a promise before returning?

回答1:

When RxJs converts an Observable to a Promise, it creates a Promise that will yield the last value from the observable. Thus the promise will not resolve until the underlying observable completes.

In your first example (and in your second as well), you never complete the red car observable. Therefore the promise never resolves. Therefore the observable that wraps the promise never produces a value...

Your 2nd example works because the subscription eagerly prints the first value produced by your red car observable as it arrives, and then "waits" for further results that never arrive.

Adding a call to onComplete should make your first version work:

observer.onNext('Red ' + car);
observer.onComplete();