JavaScript Promise.try() runs a callback and wraps its outcome in a Promise. The callback may return a normal value, throw an error, or return another Promise. Your following .then() and .catch() handlers can process all three cases through one consistent chain.
This method is useful when your code calls a function whose behavior is not fully predictable. A plugin, configuration reader, validation rule, or user callback may work synchronously today and return a Promise later.
Promise.try() Syntax
Pass the function itself as the first argument. You may provide additional arguments after it; Promise.try() forwards them to the callback.
Syntax:
Promise.try(callback)
Promise.try(callback, argument1, argument2)
| Callback outcome | Resulting Promise |
|---|---|
| Returns a normal value | Fulfilled with that value |
| Throws an error | Rejected with that error |
| Returns a fulfilled Promise | Fulfilled with its final value |
| Returns a rejected Promise | Rejected with the same reason |
Handle a Value or a Thrown Error
The following function parses stored JSON. A valid string returns an object, while malformed JSON throws a SyntaxError. Promise.try() turns the thrown error into a rejection.
Example:
// This callback can return an object or throw before returning.
function readProfile() {
const profile = '{"name":"Ava","points":42}';
return JSON.parse(profile);
}
Promise.try(readProfile)
.then(user => console.log(user.name, user.points))
.catch(error => console.error(error.message));
Output:
Ava 42
Use the Run Code button to execute a browser example. Change the JSON string so it is invalid and the same chain will display the parsing error.
Why Promise.resolve(callback()) Is Different
This expression looks similar, but JavaScript must call callback() before it can pass the result to Promise.resolve(). If that call throws, no Promise is created and a later .catch() cannot receive the error.
// A synchronous throw escapes before Promise.resolve() runs.
Promise.resolve(callback()).catch(handleError);
Passing the callback to Promise.try() gives the method control of the call, so it can translate a synchronous throw into a rejected Promise.
// Promise.try() catches a synchronous throw as a rejection.
Promise.try(callback).catch(handleError);
Work with Synchronous and Asynchronous Functions
A single helper can call functions that use either style. The consumer does not need to test the returned value with instanceof Promise.
Example:
function getLocalRate(currency) {
// A synchronous source returns immediately.
if (currency === "INR") return 83.25;
// A remote source returns a Promise.
return fetch("/api/rates/" + currency)
.then(response => {
if (!response.ok) throw new Error("Rate unavailable");
return response.json();
})
.then(data => data.rate);
}
Promise.try(getLocalRate, "INR")
.then(rate => console.log("Rate:", rate))
.catch(error => console.error(error.message));
Output:
Rate: 83.25
Pass Arguments Without an Extra Wrapper
Additional arguments avoid creating a new arrow function only to call the target function. This also keeps the original callback and its arguments separate.
Example:
function calculateTotal(price, quantity) {
// Reject invalid input with a normal synchronous error.
if (quantity < 1) throw new RangeError("Quantity must be positive");
return price * quantity;
}
Promise.try(calculateTotal, 799, 2)
.then(total => console.log("Total:", total))
.catch(error => console.error(error.message));
Output:
Total: 1598
Execution Timing
Promise.try() invokes its callback synchronously. Promise reaction handlers still run asynchronously in the microtask queue. This distinction matters when the callback changes shared state.
console.log("Before");
Promise.try(() => {
console.log("Callback"); // Runs during the current call
return "Done";
}).then(console.log); // Runs in a microtask
console.log("After");
Output:
Before
Callback
After
Done
Fallback for Older Environments
Current browsers support Promise.try(), but older environments may not. Use feature detection when your supported browser list includes them.
// Preserve the same value, error, and Promise handling behavior.
const tryPromise = Promise.try ?? ((callback, ...args) =>
new Promise((resolve, reject) => {
try {
resolve(callback(...args));
} catch (error) {
reject(error);
}
})
);
Best Practices
- Pass the callback instead of calling it before
Promise.try(). - Use normal Promise error handling after the call.
- Do not use it merely to wrap a value;
Promise.resolve(value)is clearer for that case. - Keep callback side effects clear because the callback begins synchronously.
- Check your runtime support before removing a fallback.
Conclusion
Promise.try() provides one entry point for callbacks that may return values, throw errors, or return promises. Use it at uncertain synchronous-asynchronous boundaries to simplify control flow while preserving standard Promise handling.