Promises in ES6

Promises are usually vaguely defined as “a proxy for a value that will eventually become available”. They can be used for both synchronous and asynchronous code flows, although they make asynchronous flows easier to reason about – once you’ve mastered promises, that is.
Consider as an example the upcoming fetch API. This API is a simplification of XMLHttpRequest. It aims to be super simple to use for the most basic use cases: making a GET request against a resource relative to the current page over http(s) – it also provides a comprehensive API that caters to advanced use cases as well, but that’s not our focus for now. In it’s most basic incarnation, you can make a request for GET foo like so.

fetch('foo')

The fetch('foo') statement doesn’t seem all that exciting. It makes a “fire-and-forget” GET request against foo relative to the resource we’re currently on. The fetch method returns a Promise. You can chain a .then callback that will be executed once the foo resource finishes loading.

fetch('foo').then(response => /* do something */)

For example,

fetch('foo', (err, res) => {
  if (err) {
    // handle error
  }
  // handle response
})

The callback wouldn’t be invoked until the foo resource has been fetched, so its execution remains asynchronous and non-blocking. Note that in this model you could only specify a single callback, and that callback would be responsible for all functionality derived from the response.
Few important points about Promises:

  • Follows the Promises/A+ specification, was widely implemented in the wild before ES6 was standarized (e.g bluebird)
  • Promises behave like a tree. Add branches with p.then(handler) and p.catch(handler)
  • Create new p promises with new Promise((resolve, reject) => { /* resolver */ })
    • The resolve(value) callback will fulfill the promise with the provided value
    • The reject(reason) callback will reject p with a reason error
    • You can call those methods asynchronously, blocking deeper branches of the promise tree
  • Each call to p.then and p.catch creates another promise that’s blocked on p being settled
  • Promises start out in pending state and are settled when they’re either fulfilled or rejected
  • Promises can only be settled once, and then they’re settled. Settled promises unblock deeper branches
  • You can tack as many promises as you want onto as many branches as you need
  • Each branch will execute either .then handlers or .catch handlers, never both
  • A .then callback can transform the result of the previous branch by returning a value
  • A .then callback can block on another promise by returning it
  • p.catch(fn).catch(fn) won’t do what you want — unless what you wanted is to catch errors in the error handler
  • Promise.resolve(value) creates a promise that’s fulfilled with the provided value
  • Promise.reject(reason) creates a promise that’s rejected with the provided reason
  • Promise.all(...promises) creates a promise that settles when all ...promises are fulfilled or 1 of them is rejected
  • Promise.race(...promises) creates a promise that settles as soon as 1 of ...promises is settled
  • Use Promisees — the promise visualization playground — to better understand promises

Leave a Comment

Your email address will not be published. Required fields are marked *