How do I convert from an ng.IPromise to an Observable

I am sorry for the ugly situation that this is, but I have no control over the result that I get.

My company is currently upgrading from angularjs to angular 7 or 8. We have some service calls that return ng.IPromise<T>. In the current service that I am working on, we are returning an Observable<T>.

The current behavior is that the chain of observables completes as undefined before the promise resolves and my site isn't updated with the correct behavior. I have tried several different approaches including:

return from(this.ecommerceApiRequestService
            .get<IAvailableQuantity>(
                `inventory/${lineItemInfo.lineItem.getUpc()}/onhand`,
            )
            .then((onhandInfo) => {
                const inStock =
                    lineItemInfo.quantityRequested <=
                    onhandInfo.availableQuantity;
                productQuantityInfo = {
                    inStock: inStock,
                    productId: lineItemInfo.lineItem.getProduct().id,
                    upc: lineItemInfo.lineItem.getUpc(),
                    onHandQuantity: onhandInfo.availableQuantity,
                };
                return productQuantityInfo;
            }) as Promise<IProductQuantityInfo>);

currently the ecommerceApiRequestService.get() returns ng.IPromise<T>. Is there a way to convert that to an Observable<T>?

1 answer

  • answered 2019-10-15 17:34 Reactgular

    The problem with using from() is that it creates the promise immediately, and not when the observable is subscribed too. Promises are also resolved immediately when they are created. This is not consistent with the lifecycle of observables.

    function foo() {
       return from(new Promise(resolver => {
          console.log('Hello World');
          resolver(true);
       }));
    }
    
    const foo$ = foo(); // prints "Hello World"
    

    The above prints "Hello World" to the console, but nothing has subscribed to the observable!

    We have to use the defer() function so that a factory function is used when someone subscribes.

    function foo() {
       return defer(() => from(new Promise(resolver => {
          console.log('Hello World');
          resolver(true);
       })));
    }
    
    const foo$ = foo(); // nothing is printed
    
    // prints "Hello World" followed by "true"
    foo$.subscribe(v => console.log(v));
    

    Based upon the sample source code you gave. It's not possible to tell if your problems originate from this side effect, but I doubt that you intend the source code to resolve promises immediately. Especially if you're referring to outside state such as the service class properties (which is a really bad practise, because your observables should be kept pure).