Reputation: 5416
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!
Upvotes: 96
Views: 169630
Reputation: 597
As most mentioned, you can simply use myObservable.toPromise()
. However, it's going to be removed in the next version of rxJs. For those who want to keep using toPromise()
however (perhaps to avoid changing it throughout multiple projects they own), you can create an 'extension method' of sorts, to have 'your own' toPromise()
that won't be deprecated. You can use this now even before it gets removed from rxJs.
declare module "rxjs" {
interface Observable<T> {
/**
* Extension method. Applies 'lastValueFrom' to Observable<T>.
*/
toPromise(): Promise<T | undefined>;
}
}
Observable.prototype.toPromise = function <T>(this: Observable<T>): Promise<T> {
return lastValueFrom(this);
};
To get this to show up everywhere, you must put this in the file that bootstraps your application. For Angular apps, that can be main.js
.
Upvotes: 0
Reputation: 12564
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();
Upvotes: 23
Reputation: 755
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
Upvotes: 0
Reputation: 6885
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.
Upvotes: 11
Reputation: 657058
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));
});
Upvotes: 143
Reputation: 2998
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');
Upvotes: 0
Reputation: 7407
toPromise is deprecated in RxJS 7.
Use:
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$);
}
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
}
Upvotes: 5
Reputation: 489
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);
});
}
Upvotes: 15
Reputation: 56936
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()
Upvotes: 13