ES2025: Promise.try
— Унифицированная обработка ошибок
try/catch
с цепочками промисов — новый Promise.try
в JavaScript обрабатывает возвращаемые значения, промисы и ошибки унифицированоВ JavaScript появилась новая утилита промиса, позволяющая сделать работу с потенциально асинхронными функциями чище и безопаснее. Promise.try
позволяет обернуть любую функцию в промис, независимо от того, асинхронная она или нет, сохраняя оптимальное время выполнения.
Суть проблемы
Работа с функциями, которые могут быть синхронными или асинхронными, требует смешивания различных шаблонов обработки ошибок:
function getUserData(id) {
// Нам нужны try/catch для синхронных ошибок
try {
validateId(id);
// Может возвращать кэшированные данные синхронно
if (id in cache) {
return cache[id];
}
// Может вернуть промис
return fetch(`/api/users/${id}`);
} catch (syncError) {
handleSyncError(syncError);
}
}
Проблема? Вы не знаете, какое поведение получите. Сейчас существует два распространённых способа решения этой проблемы, и оба не идеальны:
// Метод 1: Использование Promise.resolve().then()
Promise.resolve().then(() => getUserData(123));
// ❌ Заставляет всё работать в асинхронно
// ❌ Даже кэшированные данные ждут следующего тика.
// ✔️ Но, по крайней мере, ловит ошибки.
// Метод 2: Использование new Promise
new Promise(resolve => resolve(getUserData(123)));
// ❌ Многословный и неуклюжий
// ❌ Легко ошибиться
// ✔️ Синхронный код выполняется немедленно
Нам нужен лучший способ:
- Выполнение синхронного кода немедленно (для повышения производительности)
- Обработка асинхронного кода по мере необходимости
- Вылавливание любых возникающих ошибок
- Всё это делается с помощью чистого, удобочитаемого синтаксиса
Решение: Promise.try
Promise.try
предоставляет единый чистый способ обработки всех случаев:
// Чистый, безопасный и оптимальный тайминг
Promise.try(() => getUserData(123))
.then(user => {
// Вызывается с:
// - Немедленные значения (из кэша)
// - Решённые значения Promise (из fetch)
})
.catch(error => {
// Ловит оба:
// - Синхронные исключения
// - Отклонённые промисы
});
Чем Promise.try
лучше
Promise.try
имеет три ключевых преимущества:
- Выполняется синхронно, когда это возможно
- Надёжно отлавливает все ошибки
- Обрабатывает синхронные и асинхронные задачи естественно
// 1. Выполняется синхронно, когда это возможно
Promise.try(() => "instant") // Выполняется немедленно
.then(x => console.log(x));
// 2. Надёжно отлавливает все ошибки
Promise.try(() => {
throw new Error('boom');
})
.catch(err => console.log('Caught:', err));
// 3. Обрабатывает синхронные и асинхронные задачи естественно
Promise.try(() => {
if (Math.random() > 0.5) {
return "sync value";
}
return fetch('/api/data');
});
Promise.try
немедленно запускает синхронный код для повышения производительности, но при этом при необходимости выполняет асинхронные операции. Отлавливает все типы ошибок с помощью одного обработчика catch
и делает это с помощью чистого, удобного для чтения синтаксиса. Думайте об этом как об эквиваленте блока try-catch
в Promise — безопасном способе выполнения кода, который может быть неудачным или асинхронным, без необходимости заранее знать, что это такое.
Это позволяет работать с функциями, изменяющими своё поведение с течением времени. Обработка ошибок остаётся неизменной независимо от того, завершается функция сразу или нужно сделать вызов API. Не нужно заворачивать всё в блоки try-catch
, а затем отдельно обрабатывать отклонённые Promise.
Справочная информация
- https://tc39.es/ecma262/#sec-promise.try
- https://tc39.es/proposal-promise-try
- https://github.com/tc39/proposal-promise-try