Observables or Promises

best-practices typescript rxjs

Introduction

Personally, I prefer working with Observables over Promises.

There are 3 reasons for it:

  1. I do not create libraries. I work on applications.

  2. Angular provides the async pipe for working with observables.

  3. Consistency. If you know that your functions will return Observables there is just one way to handle it.

So, most of the time, if I encounter a library that exposes its functionality using Promises, I create a wrapper class around it that returns Observables.

Now, there are rules that one must remember when converting Promises to Observable. We will discuss these rules later in the post.

First, we clarify a few concepts.

Concepts

Promises

  • A Promise is something that will publish a value in the future.

  • The resolve function is used to publish that value.

  • The then method is used to listen for that value.

  • Only one value can be published.

  • Works asynchronously.

Observables

  • An Observable listens for values published by a source.

  • The subscribe method is used to listen for values.

  • Subject and BehaviourSubject publish values using their next, complete and error methods.

  • rxjs provides methods like from, Of, fromEvent and fromEventPattern that publish values.

Hot Observables

  • An Observable that does not need a subscription to publish a value.

  • A mouse click or a keyboard event are examples of hot observables as they keep publishing events regardless if someone is listening to them.

Cold Observables

  • A cold observable only publishes a value on subscriptions.

  • An Http request is an example. It only sends a server request when someone subscribes to it.

Rules to consider when converting Promises to Observables.

Using from()

const observable$ = from(getPromise());
  • This is a hot observable.

  • It is a hot observable because the producer (the Promise) is created outside of the Observable.

  • The promise executes immediately and the value is published.

  • All subscribers share the same promise and will receive the same value.

Using defer()

const observable$ = defer(()) => getPromise());
  • This is a cold observable.

  • It is a cold observable because the producer (the Promise) is created inside of the Observable.

  • The promise is executed only when someone subscribes to it.

  • Each subscriber gets a new promise and potentially a different value.

Using other operators

  • 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

  • Check the documentation for appropriate usage.

Conclusion

In summary, based on the scenario, you need to decide if you need a hot or cold observable or use one of the existing RxJS operators.

References