94

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!

Dave
  • 5,283
  • 7
  • 44
  • 66
  • The Most answers below have [`toPromise()`](https://www.learnrxjs.io/operators/utility/topromise.html) operator, that has been deprecated in RxJS 5.5+ – Rohit Sharma Sep 07 '18 at 20:32

8 Answers8

142

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));
});
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
23

observable can be converted to promise like this:

import { firstValueFrom, lastValueFrom } from 'rxjs';
...
lastValueFrom(observable).then(lastValue=>...);
firstValueFrom(observable).then(firstValue=>...);

toPromise() was the previous solution, deprecated from RxJS 7, it was:

let promise=observable.toPromise();


 
Luca C.
  • 11,714
  • 1
  • 86
  • 77
13

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

danday74
  • 52,471
  • 49
  • 232
  • 283
13

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);
    });
}
Teodor Hirs
  • 449
  • 5
  • 8
  • 2
    This can be further simplified to `return new Promise((resolve, reject) => this.getAssetTypes().subscribe(resolve, reject));` – mopo922 Dec 18 '18 at 16:34
11

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.

Emeric
  • 6,315
  • 2
  • 41
  • 54
5

toPromise is deprecated in RxJS 7.

Use:

  1. lastValueFrom

Used when we are interested in the stream of values. Works like the former toPromise

Example

public async getAssetTypes() {
  const assetTypes$ = this._APIService.getAssetTypes()
  this.assetTypes = await lastValueFrom(assetTypes$);
}
  1. firstValueFrom

Used when we are not interested in the stream of values but just the first value and then unsubscribe from the stream

public async getAssetTypes() {
  const assetTypes$ = this._APIService.getAssetTypes()
  this.assetTypes = await firstValueFrom(assetTypes$); // get first value and unsubscribe
}
SimplGy
  • 20,079
  • 15
  • 107
  • 144
Alf Moh
  • 7,159
  • 5
  • 41
  • 50
0

You can convert Observable to promise just by single line of code as below:

let promisevar = observable.toPromise()

Now you can use then on the promisevar to apply then condition based on your requirement.

promisevar.then('Your condition/Logic');
Nikunj Kakadiya
  • 2,689
  • 2
  • 20
  • 35
0

I like it raw so this one since toPromise() is no more

   const status = await new Promise<boolean>((resolve, reject) => {
     someObs$.subscribe({
      next: resolve,
      error: reject,
    });
  });

A sophisticated way is using https://rxjs.dev/api/index/function/lastValueFrom

  const replyTo = new AsyncSubject();

  replyTo.next(false);
  replyTo.next(false);
  replyTo.next(true);

  replyTo.complete();

  const status = await lastValueFrom(replyTo) // true
Divek John
  • 623
  • 8
  • 16