JavaScript Thenable Objects and Promise.resolve()

Learn JavaScript thenables, Promise.resolve adoption, thenable vs promise differences, and how thenable objects work with await.

Published

Updated

Read time 3 min read

Reviewed byDeepak Prasad

JavaScript Thenable Objects and Promise.resolve()

A thenable is any object with a callable then() method. Promises are thenable, but not every thenable is a real Promise. JavaScript treats thenables as promise-like values and can adopt them with Promise.resolve() or await.

This matters when you work with libraries, custom async wrappers, or objects that behave like promises without being created by the Promise constructor. For related promise behavior, see JavaScript Promise.resolve() and JavaScript Promise.reject().

Tested on: Node.js v20.18.2. A short note after each runnable snippet describes what you should see in the console.


Quick reference

Situation What to do
Unknown value might be Promise or thenable Promise.resolve(x) then chain .then / await
Implement minimal interop Provide then(onFulfilled, onRejected) like Promises do
Prefer real Promises in your public API Wrap with Promise.resolve before returning

Method 1: A minimal thenable

A thenable only needs a then method that eventually calls resolve or reject.

javascript
const thenable = {
  then(resolve) {
    resolve("thenable resolved");
  },
};

console.log("has-then:", typeof thenable.then);
Output

You should see one line logging has-then: function.

Promise.resolve() and await can adopt this object even though it is not a Promise instance.


Method 2: Resolve a thenable with Promise.resolve

Promise.resolve flattens thenables into the same microtask flow as native promises.

javascript
const thenable = {
  then(resolve) {
    resolve("thenable resolved");
  },
};

Promise.resolve(thenable).then((value) => {
  console.log("thenable:", value);
});
Output

You should see one line logging thenable: thenable resolved.


Method 3: await adopts a thenable

Inside an async function, await uses the same adoption rules as Promise.resolve.

javascript
const thenable = {
  then(resolve) {
    resolve("thenable resolved");
  },
};

(async () => {
  const value = await thenable;
  console.log("awaited:", value);
})();
Output

You should see one line logging awaited: thenable resolved.


Method 4: Thenable vs real Promise

Both can carry a fulfilled value, but only a real Promise is an instance of Promise and passes Promise-specific checks you might use in tests.

javascript
const promise = Promise.resolve("ready");
const customThenable = {
  then(resolve) {
    resolve("ready");
  },
};

console.log("promise-instance:", promise instanceof Promise);
console.log("thenable-instance:", customThenable instanceof Promise);
Promise.all([promise, Promise.resolve(customThenable)]).then((vals) => {
  console.log("merged:", vals.join("|"));
});
Output

You should see three lines, in order: promise-instance: true, thenable-instance: false, merged: ready|ready.

When you normalize unknown inputs, Promise.resolve(x) is a practical bridge because it accepts both promises and thenables.


Common questions about thenables

What is a thenable in JavaScript?

A thenable is an object that has a then() method and can be treated like a promise-like value.

Is every promise a thenable?

Yes. A Promise has a then() method, so it is thenable. The reverse is not true.

What is the difference between thenable and promise?

A Promise is a native async object with extra methods (catch, finally, …). A thenable is any object that implements then() and can be adopted by Promise APIs.

When should I use Promise.resolve with a thenable?

Use Promise.resolve() when a helper returns a promise-like object and you want a real Promise for chaining or async/await.


Summary

A JavaScript thenable is a promise-like object with a then() method. Use Promise.resolve() or await to adopt thenables into normal promise flow. This pattern matters when you work with custom async wrappers or libraries that return promise-compatible objects instead of native promises—especially next to Promise.resolve() and Promise.reject().


Official documentation

Olorunfemi Akinlua

Boasting over five years of experience in JavaScript, specializing in technical content writing and UX design. With a keen focus on programming languages, he crafts compelling content and designs …