Do Observables replace Promises?

Promise

  1. One value — a promise will resolve to only one value (or reject). Once resolved its value will not change.
  2. Eager — a promise is already on its way to resolve. The underlying functionality that affects the result of your promise is already in progress.
  3. Has value — a promise will always resolve to a value (or reject) and that value will never change (immutable), regardless of when you listen to the promise.
  4. Async — a promise is always asynchronous. Even when you use Promise.resolve(“done”) to create a promise it does not resolve to the value “done” synchronously.
  5. Not cancellable — synonymous to the point 2, you cannot affect the underlying functionality that resolves/rejects the promise, thus you cannot cancel it.
  6. Multicast — any number of consumers can listen to the same promise (by calling then). They will all be listening to the same source and would receive the same result at the same time (each then callback will fire in the order they were registered).
  7. Limited Operations — promises come with the predefined set of native features, which enable you to do quite a few things including combine, chain, or race promises. You can also map promise values using then. A lot can be done using these.

Observable

  1. One or more values — an observable can emit one or multiple values. You can only know how many values an observable will emit once it completes.
  2. Eager or lazy—this depends on the Temperature of the observable. The underlying functionality that affects the observable can already be in progress (with a Hot observable) OR could only be started by subscribing to it (with a Cold observable).
  3. May have value — the behaviour depends on the Temperature of the observable. If the observable is eager (hot), then you will only receive values emitted after your subscribe and until you unsubscribe. If the observable is lazy (cold), it only emits after you subscribe up until you unsubscribe.
  4. Sync or async — observables created using some creation operators are synchronous (ex: range(1, 5), of(‘jump’), from([9,8]) etc), while others are asynchronous (ex: interval(100), fromEvent() etc). When you use the create operator you can make it either a sync or async observable.
  5. May be cancellable — just as in point 2 this depends on the Temperature of the observable. Cold observables can cancel the underlying functionality just as they can start them. However the cancel-lability of a Hot observable is subjective. See below for more.
  6. Unicast or multicast — again depends on the Temperature of the observable. Hot observables will multicast > meaning all subscribers of a hot observable are listening to the same stream. Whereas cold observables will unicast > meaning each subscriber starts a new stream and will be the only listener of that stream.
  7. Operators — RxJS provides powerful methods with its constructs that enable you do pretty much anything with your Observables and their output. See docs.

Use Cases — Observable or Promise

Let’s look at a few use-cases and describe their requirements using above features to define the best construct to use.

HTTP Call

A simple http GET or POST call to an end point.

  • Requirements — One response, Eager, always async, not cancellable, must not lose response, multicast.
  • Conclusion — Promise is a clear winner.
  • Rationale — We may argue that a lazy observable is useful because the consumer can decide when to make the http call (by subscribing). However this would also mean the observable would hide the details of the http call within (endpoint, method, params etc) and allow a consumer to only make the call. Also such observable will make http calls every time someone subscribes. All of this is quite unnatural to the requirement of making an HTTP call.

UI events

Listening to UI events on the front end.

  • Requirements — Multiple events, eager, async, not cancellable, may emit while not listening, multicast, operators can be useful.
  • Conclusion — Hot Observable.
  • Rationale — Since the nature of the functionality is having multiple events, Promise is not a good option. The fact that the event generation is not controlled by the consumer makes this a clear case of a Hot Observable.

Receive WebSocket Messages

Listening to messages received on a websocket connection.

  • Requirements — Multiple messages, eager or lazy, async, cancellable, ideally don’t want to lose any messages, unicast or multicast, operations can be useful.
  • Conclusion — Warm Observable ( 🤯 WTF?). Cold Observable and Hot Observable are also applicable.
  • Rationale — Ideal implementation is to have Cold Observable that would open the websocket during the first subscribe and then convert into a Hot Observable (eager, multicast, not cancellable). The Observable would turn cold after everyone unsubscribes (by making it cancellable). This is a form of a Warm Observable. See my post on Cancelling Observables for more on this.

Read Full File

Read a full file on disk. A typical fs.readFile type thing that would return you the contents of the file.

  • Requirements — One value of file contents, eager or lazy, async, may be cancellable, always should contain same contents, multicast.
  • Conclusion —Ideally a Promise.
  • Rationale — While Promise might be ideal here there are some rare cases we may make use of features such as cancelling the file read or even starting the file read lazy. Honestly I cant think of any valid use cases these requirements off the top of my head.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store