Thenables in JavaScript

Apr 17, 2020

In JavaScript, a thenable is an object that has a then() function. All promises are thenables, but not all thenables are promises.

Many promise patterns, like chaining and async/await, work with any thenable. For example, you can use thenables in a promise chain:

// A thenable is an object with a `then()` function. The
// below thenable behaves like a promise that fulfills with
// the value `42` after 10ms.
const thenable = {
  then: function(onFulfilled) {
    setTimeout(() => onFulfilled(42), 10);
  }
};

Promise.resolve().
  then(() => thenable).
  then(v => {
    v; // 42
  });

You can also use thenables with await:

// A thenable is an object with a `then()` function. The
// below thenable behaves like a promise that fulfills with
// the value `42` after 10ms.
const thenable = {
  then: function(onFulfilled) {
    setTimeout(() => onFulfilled(42), 10);
  }
};

const v = await thenable;
v; // 42

Thenables in the Wild

Many libraries implement thenables to enable async/await support. For example, Mongoose queries are thenables, although they also have an exec() function that returns a promise. Superagent is a popular HTTP client that also uses thenables. However, neither Mongoose queries nor Superagent requests are actually promises.

Other libraries use promises directly. For example, Axios requests are promises in the sense that they are instanceof Promise.

You can convert an arbitrary thenable to a promise using Promise.resolve():

// A thenable is an object with a `then()` function. The
// below thenable behaves like a promise that fulfills with
// the value `42` after 10ms.
const thenable = {
  then: function(onFulfilled) {
    setTimeout(() => onFulfilled(42), 10);
  }
};

const p = Promise.resolve(thenable);
p instanceof Promise; // true

const v = await p;
v; // 42

More Fundamentals Tutorials