Use from
to directly convert a previously created Promise to an Observable.
import { from } from 'rxjs';
// getPromise() is called once, the promise is passed to the Observable
const observable$ = from(getPromise());
observable$
will be a hot Observable that effectively replays the Promises value to Subscribers.
It's a hot Observable because the producer (in this case the Promise) is created outside of the Observable. Multiple subscribers will share the same Promise. If the inner Promise has been resolved a new subscriber to the Observable will get its value immediately.
Use defer
with a Promise factory function as input to defer the creation and conversion of a Promise to an Observable.
import { defer } from 'rxjs';
// getPromise() is called every time someone subscribes to the observable$
const observable$ = defer(() => getPromise());
observable$
will be a cold Observable.
It's a cold Observable because the producer (the Promise) is created inside of the Observable. Each subscriber will create a new Promise by calling the given Promise factory function.
This allows you to create an observable$
without creating and thus executing a Promise right away and without sharing this Promise with multiple subscribers.
Each subscriber to observable$
effectively calls from(promiseFactory()).subscribe(subscriber)
. So each subscriber creates and converts its own new Promise to a new Observable and attaches itself to this new Observable.
Most RxJS operators that combine (e.g. merge
, concat
, forkJoin
, combineLatest
...) or transform observables (e.g. switchMap
, mergeMap
, concatMap
, catchError
...) accept promises directly. If you're using one of them anyway you don't have to use from
to wrap a promise first (but to create a cold observable you still might have to use defer
).
// Execute two promises simultaneously
forkJoin(getPromise(1), getPromise(2)).pipe(
switchMap(([v1, v2]) => v1.getPromise(v2)) // map to nested Promise
)
Check the documentation or implementation to see if the operator you're using accepts ObservableInput
or SubscribableOrPromise
.
type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;
// Note the PromiseLike ----------------------------------------------------v
type SubscribableOrPromise<T> = Subscribable<T> | Subscribable<never> | PromiseLike<T> | InteropObservable<T>;
The difference between from
and defer
in an example: https://stackblitz.com/edit/rxjs-6rb7vf
const getPromise = val => new Promise(resolve => {
console.log('Promise created for', val);
setTimeout(() => resolve(`Promise Resolved: ${val}`), 5000);
});
// the execution of getPromise('FROM') starts here, when you create the promise inside from
const fromPromise$ = from(getPromise('FROM'));
const deferPromise$ = defer(() => getPromise('DEFER'));
fromPromise$.subscribe(console.log);
// the execution of getPromise('DEFER') starts here, when you subscribe to deferPromise$
deferPromise$.subscribe(console.log);