JavaScript Promise.withResolvers()

JavaScript Tutorials


JavaScript Promise.withResolvers() creates a promise together with its resolve and reject functions in one step. It is useful when the code that settles a promise lives outside the promise constructor, such as an event callback, queue handler, stream adapter, or another asynchronous API.

The method is part of modern ECMAScript and returns an object containing three properties: promise, resolve, and reject. You can keep the promise for consumers while passing the settlement functions to the code that controls completion.

Promise.withResolvers() Syntax

// Create a promise and keep its settlement functions.
const { promise, resolve, reject } = Promise.withResolvers();
  • promise is the newly created Promise object.
  • resolve fulfills the promise with a value or adopts another promise-like result.
  • reject rejects the promise with a reason, usually an Error object.

A promise can settle only once. Later calls to resolve() or reject() do not change its settled state.

Create and Resolve a Promise

The following example creates the promise first and resolves it from code outside a Promise constructor callback.

Example:

const { promise, resolve } = Promise.withResolvers();

console.log("Created: pending");

// Resolve the promise from code outside an executor.
setTimeout(() => resolve("Order ready"), 0);

promise.then(value => {
  console.log("Resolved: " + value);
});

Output:

Created: pending
Resolved: Order ready

Reject a Promise

Keep the reject function when an external operation can fail. Rejecting with an Error object preserves a useful message and stack information.

Example:

const { promise, resolve, reject } = Promise.withResolvers();

function finishDownload(success) {
  if (success) {
    resolve("Download complete");
  } else {
    reject(new Error("Download failed"));
  }
}

promise
  .then(result => console.log(result))
  .catch(error => console.log(error.message));

finishDownload(false);

Output:

Download failed

Why Use Promise.withResolvers()?

You can already expose resolve and reject by assigning them from inside a Promise constructor. Promise.withResolvers() removes that setup code and keeps the three related values together.

Approach Typical use Key difference
new Promise() Start work immediately inside an executor Settlement functions begin inside the constructor callback
Promise.withResolvers() Connect later or external completion events Promise and settlement functions are returned together

Use the ordinary constructor when the asynchronous work naturally starts in the executor. Use Promise.withResolvers() when promise creation and promise settlement belong to different parts of the program.

Wrap an Event-Style Operation

A common pattern is to create a promise now and settle it later when an event or callback arrives. The promise can be returned immediately while another function keeps the settlement controls.

Example:

function createSignal() {
  const controls = Promise.withResolvers();

  return {
    wait: () => controls.promise,
    complete: value => controls.resolve(value),
    fail: reason => controls.reject(reason)
  };
}

const signal = createSignal();

signal.wait().then(value => {
  console.log("Received:", value);
});

// Some later event can complete the pending work.
signal.complete("Payment confirmed");

Output:

Received: Payment confirmed

Do Not Reuse a Settled Promise

Promise.withResolvers() creates one promise with one lifetime. If you are processing several independent events, create a fresh resolver set for each event instead of trying to reset an existing promise.

For example, a queue may hold one pending resolver set. After an item arrives and resolves that promise, the queue can create another resolver set for the next waiting consumer.

Error Handling

The returned promise behaves like any other JavaScript promise. You can use then(), catch(), finally(), await, Promise.all(), and other promise operations normally.

  • Attach a rejection handler when failure is possible.
  • Reject with Error objects instead of plain strings when practical.
  • Do not expose resolve and reject more widely than necessary.
  • Clean up event listeners or external resources when the operation settles.

Common Mistakes

  • Expecting multiple results: one promise represents one eventual settlement. Use an async iterator, stream, or event system for repeated values.
  • Forgetting rejection handling: an unhandled rejected promise can produce runtime warnings or terminate some server processes depending on configuration.
  • Keeping resolvers forever: long-lived references can retain related data unnecessarily. Release them when the operation finishes.
  • Using it when the constructor is clearer: if all work starts inside one executor, new Promise() can be easier to read.

Best Practices

  • Keep the resolver object close to the resource or event that controls completion.
  • Return only the promise to consumers when they should not control settlement.
  • Create a new resolver set for every logically separate asynchronous operation.
  • Use finally() or equivalent cleanup logic when listeners, timers, or handles must be released.

Conclusion

Promise.withResolvers() provides a direct way to create a promise and obtain its resolve and reject functions at the same time. It is most useful when promise creation and completion happen in different places. Use it for callback or event adapters, one-shot signals, and queue-style coordination while keeping ownership of the settlement functions clear.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram