I shipped skillcraft.ai !!!
Skillcraft helps you find the best learning resources tailored to your goals. Get a personalized roadmap with the best courses, books, and tutorials. Try it out, for free!
Up to date
Published
3 min read

Trevor I. Lasn

Building tools for developers. Currently building skillcraft.ai and blamesteve.lol

Promise.try: Unified Error Handling for Sync and Async JavaScript Code (ES2025)

Stop mixing try/catch with Promise chains - JavaScript's new Promise.try handles return values, Promises, and errors uniformly

JavaScript is getting a new Promise utility that makes handling potentially async functions cleaner and safer. Promise.try lets you wrap any function in a Promise, whether it’s async or not, while maintaining optimal execution timing.

The Core Problem

Handling functions that might be sync or async requires mixing different error handling patterns:

JavaScript
function getUserData(id) {
// We need try/catch for sync errors
try {
validateId(id);
// Might return cached data synchronously
if (id in cache) {
return cache[id];
}
// Might return a Promise
return fetch(`/api/users/${id}`);
} catch (syncError) {
handleSyncError(syncError);
}
}

The problem? You never know which behavior you’ll get. Currently, there are two common ways to handle this, but neither is ideal:

JavaScript
// Method 1: Using Promise.resolve().then()
Promise.resolve().then(() => getUserData(123));
// ❌ Forces everything to be async
// ❌ Even cached data waits for the next tick
// ✓ But at least it catches errors
// Method 2: Using new Promise
new Promise(resolve => resolve(getUserData(123)));
// ❌ Verbose and clunky
// ❌ Easy to get wrong
// ✓ Runs sync code immediately

We need a better way to:

  • Run synchronous code immediately (for better performance)
  • Handle asynchronous code when needed
  • Catch any errors that might occur
  • Do all this with clean, readable syntax

The Solution: Promise.try

Promise.try gives us one clean way to handle all cases:

JavaScript
// Clean, safe, and optimal timing
Promise.try(() => getUserData(123))
.then(user => {
// Gets called with:
// - Immediate values (from cache)
// - Resolved Promise values (from fetch)
})
.catch(error => {
// Catches both:
// - Synchronous throws
// - Promise rejections
});

Why It’s Better

Promise.try has three key advantages:

JavaScript
// 1. Runs synchronously when possible
Promise.try(() => "instant") // Executes immediately
.then(x => console.log(x));
// 2. Catches all errors reliably
Promise.try(() => {
throw new Error('boom');
})
.catch(err => console.log('Caught:', err));
// 3. Handles both sync and async naturally
Promise.try(() => {
if (Math.random() > 0.5) {
return "sync value";
}
return fetch('/api/data');
});

Promise.try runs synchronous code immediately for better performance, while still handling async operations when needed. It catches every type of error through a single catch handler, and does it all with clean, readable syntax. Think of it as the Promise equivalent of a try-catch block - a safe way to execute code that might fail or might be async, without having to know which it is ahead of time.

This is particularly powerful when working with functions that might change their behavior over time. Your error handling remains consistent whether the function returns immediately or needs to make an API call. No more wrapping everything in try-catch blocks and then also handling Promise rejections separately.

References


Found this article helpful? You might enjoy my free newsletter. I share dev tips and insights to help you grow your coding skills and advance your tech career.


Check out these related articles that might be useful for you. They cover similar topics and provide additional insights.

Javascript
3 min read

JavaScript's ??= Operator: Default Values Made Simple

A guide to using ??= in JavaScript to handle null and undefined values elegantly

Nov 5, 2024
Read article
Javascript
6 min read

AggregateError in JavaScript

Handle multiple errors at once

Sep 2, 2024
Read article
Javascript
4 min read

Intl.DurationFormat: Format Time Durations with Locale Support

Stop writing manual duration formatting code. Instead, leverage the new powerful Intl.DateTimeFormat API for internationalized time displays

Mar 13, 2025
Read article
Javascript
4 min read

Error.isError(): A Better Way to Check Error Types in JavaScript

Why the new Error.isError() method solves important cross-realm issues and provides more reliable error identification than instanceof

May 9, 2025
Read article
Javascript
7 min read

JavaScript Truthy and Falsy: A Deep Dive

Grasp JavaScript's type coercion with practical examples and avoid common pitfalls

Oct 27, 2024
Read article
Javascript
4 min read

The Only Widely Recognized JavaScript Feature Ever Deprecated

The 'with' statement is the only feature ever deprecated in JavaScript

Aug 22, 2024
Read article
Javascript
5 min read

Working with JavaScript's Scheduler API

Learn how to prioritize and control task execution in JavaScript using the new Scheduler API for better performance and user experience

Nov 26, 2024
Read article
Javascript
3 min read

Float16Array in JavaScript

Understanding the new 16-bit floating point array in JavaScript

Apr 14, 2025
Read article
Javascript
4 min read

JavaScript compile hints: what they are and when to use them

V8's compile hints let you control which JavaScript gets compiled immediately during page load

May 12, 2025
Read article

This article was originally published on https://www.trevorlasn.com/blog/promise-try-in-javascript. It was written by a human and polished using grammar tools for clarity.