Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

http provider Observable.toPromise() not working as expected in promise chains

If i call a promise enabled method using the ng2 http provider Observable.toPromise() support it works as expected but when i use it as part of promise chain it resolves the returned promise before the then handler has processed and returned the result.

Any known issues with getting Observable.toPromise() to work in promise chains or alternative ways i might test to make it a promise chain compatible result? I'm blocked by this resolving promise before the http request, last item in promise chain, has completed its async request and returned result.

For example

this.myService.getSomethingInvolvingingMultiplePromiseCalls().then(result => {
    let valueFromSomethingInvolvingMultiplePromiseCalls = result;
}, err => { 
    console.error('landed in app.component outer promise rejected handler, see output window for details')
})

public getSomethingInvolvingingMultiplePromiseCalls(): Promise<string> {
    return this.getSomethingInvolvingPromiseCall().then(resultPromise1 => {
        let resultPromise1propertyFoo = resultPromise1.propertyFoo;
            return this.getSomethingInvolvingNg2HttpProviderToPromiseCall(resultPromise1propertyFoo);
        }
        .then(resultPromise2 => {
            let resultPromise2propertyBar = resultPromise2.propertyBar;
            return resultPromise2propertyBar;
        }   
    }

getSomethingInvolvingNg2HttpProviderToPromiseCall(arg1: string): Promise<string> {
   let body = 'some body content leveraging arg1';
   let headers = new Headers({ 'Authorization': 'Bearer ' + accessToken, 'Content-Type': 'application/x-www-form-urlencoded' });
   let options = new RequestOptions({ headers: headers });

   return this.http.post(resourceBaseAddress + '/someRestApi', body, options).toPromise().then(response => {
        let responseJson = response.json();
        return responseJson['someJsonProperty'];
      });
    }
}

thanks in advance for any insights or suggestions.

like image 572
myusrn Avatar asked Feb 20 '16 21:02

myusrn


2 Answers

I found a resolution to this.

It involved creating and returning a typescript deferred promise that I control resolving only when I landed inside of then handler for call to method using angular2 http provider toPromise().

Something I didn't have to do with other promise chaining scenarios but for whatever reason in this case allowed by to park method caller until the http provider toPromise() call in the chain completed.

public getSomethingInvolvingingMultiplePromiseCalls(): Promise<string> {
    let resolveFn, rejectFn;
    let promise = new Promise((resolve, reject) => { resolveFn = resolve; rejectFn = reject; });

    this.getSomethingInvolvingPromiseCall().then(resultPromise1 => {
        this.getSomethingInvolvingNg2HttpProviderToPromiseCall(resultPromise1).then(resultPromise2 => resolveFn(resultPromise2));
    }

    return promise;  // return the promise for outside callers to wait on
}
like image 73
myusrn Avatar answered Nov 12 '22 16:11

myusrn


See the below working example of an observable in a promise chain.

var promise = new Promise((resolve, reject) => {
  resolve(3)
}).then((num) => {
  return Rx.Observable.create((observer) => {
    setTimeout(() => {
      observer.next(5);
      observer.onCompleted();
    }, 0)
  }).toPromise()
}).then((num) => {
  return num * 2;
})

promise.then((number) => {
  alert(number);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>

One gotcha if your using .toPromise() is that observer.onCompleted() must be called. If your converting an observable that does not complete your promise will not resolve.

like image 26
Daniel Rasmuson Avatar answered Nov 12 '22 14:11

Daniel Rasmuson