乐闻世界logo
搜索文章和话题

How to convert Promise to Observable

5个答案

1
2
3
4
5

In RxJS, converting a Promise to an Observable is a common operation that can be achieved using utility functions provided by RxJS. Specifically, you can use the from function to perform this conversion. The from function can convert arrays, array-like objects, Promises, and iterators into Observables.

Here is a specific example of converting a Promise to an Observable:

javascript
import { from } from 'rxjs'; // Assume we have a function that returns a Promise function fetchData() { return new Promise(resolve => { setTimeout(() => { resolve('Data loaded'); }, 1000); }); } // Use `from` to convert the Promise to an Observable const dataObservable = from(fetchData()); // Subscribe to the Observable to handle the data dataObservable.subscribe({ next(data) { console.log(data); // Output: Data loaded }, error(err) { console.error('Something wrong occurred: ' + err); }, complete() { console.log('Done'); } });

In the above code snippet, the fetchData function returns a Promise that resolves after 1 second. We convert this Promise into an Observable using the from function and subscribe to the Observable via the subscribe method so that we can receive the data and process it once the Promise resolves.

The method of converting a Promise to an Observable using the from function is simple and powerful, as it seamlessly integrates Promises into RxJS's reactive programming paradigm, enabling more flexible and powerful handling of asynchronous operations.

2024年6月29日 12:07 回复

You can wrap the Promise functionality to convert it into an Observable that can be observed by the subscriber.

  • Use the defer() operator to create a Lazy Observable, which allows you to create the Observable only when the subscriber subscribes.
typescript
import { of, Observable, defer } from 'rxjs'; import { map } from 'rxjs/operators'; function getTodos$(): Observable<any> { return defer(() => { return fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) .then(json => { return json; }) }); } getTodos$() .subscribe( (next) => { console.log('Data is:', next); } )
2024年6月29日 12:07 回复

The correct approach to convert a Promise to an Observable is to use the defer and from operators:

typescript
import { defer, from } from 'rxjs'; const observable$ = defer(() => from(myPromise()));

Why do we need the defer operator?

Promises are eager, meaning they trigger immediately when called. This is the opposite of how Observables work. Observables are lazy, meaning they only trigger when .subscribe() is called. This is why we always need to wrap it with the defer operator. The from operator does not perform this work, so defer is always required.

2024年6月29日 12:07 回复

Here's an example:

javascript
import 'rxjs/add/observable/fromPromise'; import { Observable } from "rxjs/Observable"; const subscription = Observable.fromPromise( firebase.auth().createUserWithEmailAndPassword(email, password) ); subscription.subscribe(firebaseUser => /* Do anything with data received */, error => /* Handle error here */);

You can find the complete reference for the fromPromise operator here: here

2024年6月29日 12:07 回复
  1. Direct Execution/Conversion
  • Use from to directly convert a previously created Promise into an Observable.
javascript
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, which can effectively replay the Promise value to subscribers.

It is a hot Observable because the producer (in this case, the Promise) is created outside the Observable. Multiple subscribers will share the same Promise. If the internal Promise has been resolved, new subscribers to the Observable will immediately receive its value.

  1. Deferred Execution per Subscription
  • Use defer with a Promise factory function as input to defer the creation and conversion of the Promise into an Observable.
javascript
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 is a cold Observable because the producer (the Promise) is created inside the Observable. Each subscriber will create a new Promise by calling the given Promise factory function.

This allows you to create a Promise observable$ without immediately creating and executing the Promise, and without sharing this Promise with multiple subscribers. Each subscriber can effectively call from(promiseFactory()).subscribe(subscriber). Thus, each subscriber creates their own new Promise and converts it to a new Observable, attaching themselves to this new Observable.

  1. Many Operators Directly Accept Promises
  • Most combination operators (e.g., merge, concat) or transformation operators (e.g., forkJoin, combineLatest, switchMap, mergeMap, concatMap, catchError) directly accept Promises. If you use any of these operators, you don't need to wrap the Promise first (but to create a cold Observable, you may still need to use defer).
javascript
// 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 are using accepts ObservableInput or SubscribableOrPromise.

typescript
type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>; // Note the PromiseLike ----------------------------------------------------v type SubscribableOrPromise<T> = Subscribable<T> | Subscribable<never> | PromiseLike<T> | InteropObservable<T>;

Difference between from and defer example: https://stackblitz.com/edit/rxjs-6rb7vf

javascript
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);

defer is likely the operator most people are looking for, as many applications rely on Observables to maintain a cold state and trigger data fetching upon subscription. However, for certain use cases, from remains a viable option, such as when you want to create a Promise once during initialization and propagate its value through an Observable that is subscribed to multiple times, without creating and executing the Promise again for each subscriber.

2024年6月29日 12:07 回复

你的答案