Thenables in JavaScript
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