Promise.try()
Calls a function and captures its return value, thrown error, or promise in one promise.
Promise.try(func)
Promise.try(func, arg1)
Promise.try(func, arg1, arg2)
Promise.try(func, arg1, arg2, /* …, */ argN)- Added in JavaScript ES2025
Parameters
| Parameter | Type | Description |
|---|---|---|
$func | Function | A function called synchronously with the arguments provided. It may return a value, throw an error, or return a promise. |
$arg1, arg2, …, argNoptional | any | Arguments passed through to func in order. |
Return value
PromiseA Promise that is already fulfilled if func returns a value synchronously, already rejected if func throws synchronously, and asynchronously fulfilled or rejected if func returns a promise.
Errors
Does not throw — a synchronous error inside func is converted into a rejection of the returned promise, and a non-callable func likewise yields a promise rejected with a TypeError rather than a synchronous throw.
Changelog
- PHP Baseline January 2025Newly available across browser engines. Older runtimes need a shim such as new Promise((resolve) => resolve(func(...args))).
Promise.try(func) calls func immediately and packages every possible outcome — a plain return, a synchronous throw, or a returned promise — into a single promise. It closes the one hole that .catch() cannot cover.
The gap it fills
A function that throws before returning a promise throws at the call site, where no promise exists yet to carry the error. risky().catch(handle) never reaches .catch() in that case; the exception escapes synchronously and your handler, your finally(), and any surrounding chain are all bypassed. Promise.try(risky).catch(handle) puts that error in the chain where you expected it.
When to reach for it
At the boundary where you invoke code you did not write: user-supplied callbacks, plugin hooks, a registry of handlers that might be sync or async. It lets you treat all of them uniformly without wrapping each call in try/catch and .catch().
Note on timing
func runs synchronously, right away — Promise.try does not defer it to a later tick. Only the settlement of the returned promise is asynchronous. Extra arguments are forwarded to func, so you rarely need a wrapping arrow function.
Example
When to use it
- Invoke a plugin hook that may be synchronous or asynchronous and handle both alike
- Bring an argument-validation throw into the promise chain instead of the call site
- Start a chain from a function without an extra Promise.resolve().then() dance
- Normalise a registry of handlers with mixed return styles
Frequently asked questions
Why not just use Promise.resolve(fn())?
Because fn() is evaluated before Promise.resolve runs, so a synchronous throw escapes at the call site. Promise.try invokes the function itself and converts that throw into a rejection.
Does Promise.try defer the function to a later tick?
No, func is called synchronously and immediately. Only the settlement of the returned promise is asynchronous.
Can I use Promise.try today?
It is Baseline as of January 2025, so current browser engines support it. For older runtimes use the one-line shim new Promise((resolve) => resolve(func(...args))).
More examples
The error that .catch() cannot see
Calling risky() directly throws before .then() is ever reached, so only a surrounding try/catch sees it. Routed through Promise.try, the same error becomes a rejection, so .catch() handles it and the .finally() cleanup still runs.
const risky = () => { throw new Error("thrown synchronously"); };
try {
risky().then(() => {});
} catch (e) {
console.log("plain call escapes the chain:", e.message);
}
await Promise.try(risky)
.catch((e) => console.log("Promise.try keeps it in the chain:", e.message))
.finally(() => console.log("finally still runs"));Uniform handling of mixed handlers
Four handlers with four different return styles are consumed by one line of code. Without Promise.try the throwing handler would need its own try/catch, because its error never reaches the then() beside it.
const handlers = [
() => "plain value",
async () => "async value",
() => Promise.resolve("promise value"),
() => { throw new Error("handler failed"); },
];
for (const h of handlers) {
console.log(await Promise.try(h).then((v) => "ok: " + v, (e) => "err: " + e.message));
}
Discussion