Promise.withResolvers()

Creates a promise together with its resolve and reject functions in the same scope.

Signature
Promise.withResolvers()
  • Added in JavaScript ES2024

Return value

{ promise: Promise, resolve: Function, reject: Function }A plain object with three properties: promise (a new Promise), resolve (a function that resolves it), and reject (a function that rejects it). The two functions have the same semantics as the ones passed to the Promise constructor's executor.

Errors

TypeError if called on a value that is not a constructor.

Changelog

  • PHP Baseline March 2024Became available across all major browser engines; older environments need a two-line polyfill built on the Promise constructor.

Promise.withResolvers() gives you a promise and the two functions that settle it as three siblings in one object, instead of trapping them inside an executor closure. It replaces the old deferred boilerplate:

let resolve, reject;
const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

When to reach for it

Whenever the thing that settles the promise is not the thing that created it. Queues where a consumer waits for a producer; a gate other code opens; an event handler registered far from the awaiting caller; wrapping a stream or a worker message. If the settlement logic fits inside the executor, keep using new Promise() — an executor keeps control local and is easier to reason about.

What trips people up

You have given away the ability to settle the promise, so it is now possible for nobody to call resolve and for the promise to hang forever with no stack trace pointing at the cause. Settlement is still one-shot: extra resolve or reject calls are silently ignored, which is convenient for "first one wins" but hides double-settle bugs.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Let an event handler resolve a promise its caller is awaiting
  • Build an async queue where consumers wait for future pushes
  • Expose a gate or barrier other modules can open
  • Bridge a callback-based worker or stream into an awaitable value

Frequently asked questions

How is Promise.withResolvers different from new Promise?

It returns the resolve and reject functions alongside the promise instead of only exposing them inside the executor, so code outside the constructor can settle the promise without an extra closure.

Is this the deferred pattern?

Yes — it is the standardised version of the let resolve, reject; new Promise(...) idiom that libraries have shipped as a Deferred object for years.

Can I call resolve twice?

You can, but only the first call has any effect. Later resolve or reject calls are silently ignored, which makes it safe for first-one-wins logic but easy to overlook a double-settle bug.

More examples

An async queue

pull() called before anything is queued parks a deferred and hands back its promise; the later push() settles it. The second pair shows the buffered path, where the value is already waiting and comes back immediately.

Example · javascript
const waiters = [];
const queue = [];

function push(v) {
  if (waiters.length) waiters.shift().resolve(v);
  else queue.push(v);
}
function pull() {
  if (queue.length) return Promise.resolve(queue.shift());
  const d = Promise.withResolvers();
  waiters.push(d);
  return d.promise;
}

const pending = pull();
push("first message");
console.log(await pending);
push("second message");
console.log(await pull());

Settlement is one-shot

The second resolve() is discarded without warning — first call wins. The gate pattern shows the usual shape: one part of the code awaits the promise while an unrelated part decides when to open it.

Example · javascript
const { promise, resolve } = Promise.withResolvers();
resolve("winner");
resolve("ignored");
console.log(await promise);

const gate = Promise.withResolvers();
let opened = false;
setTimeout(() => { opened = true; gate.resolve(); }, 10);
await gate.promise;
console.log("gate opened:", opened);

Discussion

  • Be the first to comment on this lesson.