Promise.withResolvers() returns a plain object { promise, resolve, reject }. It replaces the old pattern of declaring let resolve, reject outside and assigning them inside the executor. Use it when the thing that settles the promise is not the code that creates it: event handlers, message queues, request/response matching, test helpers, or a "ready" signal. It is the same promise with the same once-only rules. The spec simply makes NewPromiseCapability available directly.
One difference from new Promise(executor): there is no executor, so there is no automatic "throw becomes rejection". Setup code you write next to it throws normally.
Promise.try(callback, ...args) calls callback(...args) immediately and synchronously, then:
- if it returns a value or a promise, the result promise resolves with it, with the usual adoption rules;
- if it throws, the result promise is rejected with the error.
It solves the "sometimes sync, sometimes async" function. Without it, fn() may throw before you get a promise, so a .catch never sees the error. Promise.resolve().then(fn) catches it but delays fn by a microtask. new Promise((resolve) => resolve(fn())) and (async () => fn())() work but are noisy. Promise.try does it in one call, and passes arguments.
Both are static methods that read this as the constructor, so they must be called as Promise.try(...), not detached.
Availability. Both run in Node 24. By MDN's browser-compat-data, withResolvers shipped in Chrome 119, Firefox 121 and Safari 17.4 (Node 22) and is Baseline widely available. try shipped in Chrome 128, Firefox 134 and Safari 18.2 (Node 23) and is Baseline newly available (since January 2025), so older browsers need a polyfill.