Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Last active May 9, 2019 18:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benjamingr/93b70845c1b9678715e5957f1cdce8a3 to your computer and use it in GitHub Desktop.
Save benjamingr/93b70845c1b9678715e5957f1cdce8a3 to your computer and use it in GitHub Desktop.

A Promise handles a single event when an async operation completes or fails.

So, a promise doesn't handle anything - a promise is just a value over time. The charactaristics of promises are that:

  • Because a promise is just a value - promises are multicast which means multiple .thens are 'transparent'.
  • Native promises are what async functions return and what they await.
  • Promises have three states (fulfilled, pending and rejected) and transition between them just once.

Promises aren't really eager - but if you have a promise an operation has already started - so terms lik running promises don't make sense. They have a built in (stage 4 and part of JavaScript) multi-value counterpart (async iterators) which do multiple values and are lazy.

Note: There are Promise libraries out there that support cancellation, but ES6 Promise doesn't so far.

That part is true.

Observable

An Observable is like a Stream (in many languages) and allows to pass zero or more events where the callback is called for each event.

So, when I said this in an Angular-beta core data team discussion with Ben Lesh he insisted it's wrong. In retrospect he was right :)

An observable is like a function - when you do new Observable(observer => { }) you are really building a function. I actually show how to build Rx here and explain this. I can't stress this enough but all an observable is is:

constructor Observable {
  constructor(subscribe) {
    this.subscribe = subscribe;
  }
}

Which lets you do:

let o = new Observable(observer => {
  let interval = setInterval(() => observer.next('hello'), 100);
  return () => clearInterval(interval);
});
// subscription is the clearInterval, this is _just_ a function call
let subscription = o.subscribe({
  next(value) { console.log(value, 'world!'); } // this is just the observer argument!
});

That's why Rx is nice, it's just a contract over functions :)

Often Observable is preferred over Promise because it provides the features of Promise and more.

That's basically like saying arrays are better than values because arrays have multiple values. I think it's confusing:

  • If you want to return a single value you should use a promise.
  • If you want to create an eager push stream over multiple values - you should use an observable.

Having a smaller API surface is generally better than a big one if possible. While RxJS is awesome I think this is risky advice.

With Observable it doesn't matter if you want to handle 0, 1, or multiple events. You can utilize the same API in each case.

That's also true with async iterators (which are stage 4 and built into and have syntax support) and any other multi-part abstraction. We're currently evaluating how to use different abstractions in Node.js core (If you want to be part of this discussion you're invited!).

Observable also has the advantage over Promise to be cancelable.

Well, a subscription is cancellable - an observable is not cancellable since it's a function and not values.

That said - an observable is not a static JavaScript feature, you are comparing apples to oranges. You are basically saying that the RxJS library is cancellable while native promises are not. That's fine - but it's important to say that.

Since an observable is just a function call, if that function (subscribe) returns a function - it can do unsubscriptions if it wants to.

If the result of an HTTP request to a server or some other expensive async operation isn't needed anymore, the Subscription of an Observable allows to cancel the subscription, while a Promise will eventually call the success or failed callback even when you don't need the notification or the result it provides anymore.

Promise based APIs do cancellation - just not through the Promise itself. For example AbortController with fetch is a DOM API that returns a promise but is cancellable.

Observable provides operators like map, forEach, reduce, ... similar to an array

That's a property of the RxJS library (or other libraries) and not the abstraction. Here is an example where I implement it over Async Iterators - note I wrote this when it was a very early stage proposal so it might be outdated.

Of course promise libraries also provide operators (namely bluebird provides .map .forEach and .reduce).

It is also a little risky to compare observables to arrays. The best explanation of Rx I know is Duality and the End of Reactive but I have to admit I saw it after using Rx for 3-4 years already.

There are also powerful operators like retry(), or replay(), ... that are often quite handy.

That's again a feature of the library and not the abstraction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment