Angular 2: Convert Observable to Promise

126,241

Solution 1

rxjs7

lastValueFrom(of('foo'));

https://indepth.dev/posts/1287/rxjs-heads-up-topromise-is-being-deprecated

rxjs6

https://github.com/ReactiveX/rxjs/issues/2868#issuecomment-360633707

Don't pipe. It's on the Observable object by default.

Observable.of('foo').toPromise(); // this

rxjs5

import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';

...

this._APIService.getAssetTypes()
.map(assettypes => {
  this._LocalStorageService.setAssetTypes(assettypes);
})
.toPromise()
.catch(err => {
  this._LogService.error(JSON.stringify(err));
});

Solution 2

observable can be converted to promise like this:

let promise=observable.toPromise();

Solution 3

you dont really need to do this just do ...

import 'rxjs/add/operator/first';


this.esQueryService.getDocuments$.first().subscribe(() => {
        event.enableButtonsCallback();
      },
      (err: any) => console.error(err)
    );
    this.getDocuments(query, false);

first() ensures the subscribe block is only called once (after which it will be as if you never subscribed), exactly the same as a promises then()

Solution 4

The proper way to make Observable a Promise, in your case would be following

getAssetTypesPromise() Observable<any> {
  return new Promise((resolve, reject) => {
      this.getAssetTypes().subscribe((response: any) => {
        resolve(response);
      }, reject);
    });
}

Solution 5

Edit:

.toPromise() is now deprecated in RxJS 7 (source: https://rxjs.dev/deprecations/to-promise)

New answer:

As a replacement to the deprecated toPromise() method, you should use one of the two built in static conversion functions firstValueFrom or lastValueFrom.

Example:

import { interval, lastValueFrom } from 'rxjs';
import { take } from 'rxjs/operators';
 
async function execute() {
  const source$ = interval(2000).pipe(take(10));
  const finalNumber = await lastValueFrom(source$);
  console.log(`The final number is ${finalNumber}`);
}
 
execute();
 
// Expected output:
// "The final number is 9"

Old answer:

A lot of comments are claiming toPromise deprecated but as you can see here it's not.

So please juste use toPromise (RxJs 6) as said:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = sample('First Example')
  .toPromise()
  //output: 'First Example'
  .then(result => {
    console.log('From Promise:', result);
  });

async/await example:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = await sample('First Example').toPromise()
// output: 'First Example'
console.log('From Promise:', result);

Read more here.


Note: Otherwise you can use .pipe(take(1)).toPromise but as said you shouldn't have any problem using above example.

Share:
126,241

Related videos on Youtube

Dave
Author by

Dave

Updated on November 24, 2021

Comments

  • Dave
    Dave over 2 years

    Q) How do I convert the following observable to a promise so I can call it with .then(...)?

    My method I want to convert to a promise:

      this._APIService.getAssetTypes().subscribe(
        assettypes => {
            this._LocalStorageService.setAssetTypes(assettypes);
        },
        err => {
            this._LogService.error(JSON.stringify(err))
        },
        () => {}
      ); 
    

    The service method it calls:

      getAssetTypes() {
        var method = "assettype";
        var url = this.apiBaseUrl + method;
    
        return this._http.get(url, {})
          .map(res => <AssetType[]>res.json())
          .map((assettypes) => {
            assettypes.forEach((assettypes) => {
              // do anything here you might need....
          });
          return assettypes;
        });      
      }  
    

    Thanks!

    • Rohit Sharma
      Rohit Sharma over 5 years
      The Most answers below have toPromise() operator, that has been deprecated in RxJS 5.5+
  • Dave
    Dave about 8 years
    Get this error: [ts] Argument of type '(assettypes: any) => void' is not assignable to parameter of type 'PromiseConstructor'. Property 'all' is missing in type '(assettypes: any) => void'. (parameter) assettypes: any
  • Günter Zöchbauer
    Günter Zöchbauer about 8 years
    What does getAssetTypes() return?
  • Dave
    Dave about 8 years
    an array of interface type AssetType
  • Günter Zöchbauer
    Günter Zöchbauer about 8 years
    It needs to return an Observable for this to work. The code in your question also only works if it returns an Observable (to call subscribe(...) on it)
  • Dave
    Dave about 8 years
    I've updated my question with the service method that is called. thanks.
  • Günter Zöchbauer
    Günter Zöchbauer about 8 years
    Ok, it returns an Observable. I updated my answer.
  • Dave
    Dave about 8 years
  • Zze
    Zze about 7 years
    @GünterZöchbauer has import 'rxjs/operator/add/toPromise'; been changed to: import 'rxjs/add/operator/toPromise'; ?
  • Flavien Volken
    Flavien Volken over 6 years
    Correct, the promise is only resolved at the time the observables completes, using .first() or .take(1) will ensure it's the case after the first emit.
  • Sampath
    Sampath about 6 years
    The problem here is we cannot use async/await pattern.
  • Jus10
    Jus10 almost 6 years
    toPromise is deprecated. How would we do this now?
  • KnowledgeSeeker
    KnowledgeSeeker almost 6 years
    If I conver this to promise I can also catch an error right?
  • Luca C.
    Luca C. almost 6 years
    you can surround with try catch and even user promise.catch()
  • mopo922
    mopo922 over 5 years
    This can be further simplified to return new Promise((resolve, reject) => this.getAssetTypes().subscribe(resolve, reject));
  • Mohit Atray
    Mohit Atray over 4 years
    first().toPromise() will give you promise and then you can use async/await
  • Emeric
    Emeric over 4 years
    It's not. Please see my answer.
  • Soroush Falahati
    Soroush Falahati over 2 years
    it is deprecated and might be removed in v8. your link is for v6.