Promise.withResolvers() нужен, когда хочется создать промис и сразу получить связанные с ним функции resolve и reject отдельно. Метод вызывается у Promise, не принимает аргументов и возвращает объект с тремя свойствами: самим промисом и двумя функциями для его завершения.
Это удобная альтернатива шаблону, где resolve и reject приходится сохранять вручную через new Promise(...).
Синтаксис
Базовая запись выглядит так:
Promise.withResolvers()
Метод не принимает обязательных аргументов.
Что возвращает Promise.withResolvers()
Метод возвращает обычный объект такого вида:
{
promise,
resolve,
reject
}
Где:
promise- созданный объектPromiseresolve- функция для успешного завершения этого промисаreject- функция для отклонения этого промиса
Пример:
const result = Promise.withResolvers();
console.log(result.promise instanceof Promise); // true
console.log(typeof result.resolve); // "function"
console.log(typeof result.reject); // "function"
Простой пример
const { promise, resolve } = Promise.withResolvers();
promise.then((value) => {
console.log(value); // "Готово"
});
resolve("Готово");
Сначала мы создаём промис, потом отдельно решаем, когда именно его завершить.
resolve() успешно завершает связанный промис
Это основное поведение метода.
const { promise, resolve } = Promise.withResolvers();
promise.then((value) => {
console.log(value); // "ok"
});
resolve("ok");
Функция resolve() работает так же, как resolve внутри обычного new Promise(...).
reject() завершает промис с ошибкой
Если нужно завершить промис неуспешно, используют reject().
const { promise, reject } = Promise.withResolvers();
promise.catch((error) => {
console.log(error.message); // "boom"
});
reject(new Error("boom"));
После этого промис переходит в состояние rejected.
Обработчики всё равно выполняются асинхронно
Это важный нюанс.
Даже если вызвать resolve() сразу, then() не выполнится синхронно в ту же строку.
console.log("start");
const { promise, resolve } = Promise.withResolvers();
promise.then((value) => {
console.log(value); // 42
});
resolve(42);
console.log("end");
Результат будет таким:
start
end
42
То есть Promise.withResolvers() не меняет стандартное асинхронное поведение промисов.
resolve() может принять другой промис
Это тоже работает так же, как у обычного resolve в конструкторе Promise.
Если передать в resolve() другой промис, итоговый промис примет его состояние.
const { promise, resolve } = Promise.withResolvers();
resolve(Promise.resolve("inner"));
promise.then((value) => {
console.log(value); // "inner"
});
То есть здесь промис не получит внутрь объект Promise, а дождётся его результата.
resolve() может принять thenable
Это ещё один полезный нюанс.
const { promise, resolve } = Promise.withResolvers();
resolve({
then(onFulfilled) {
onFulfilled("thenable");
},
});
promise.then((value) => {
console.log(value); // "thenable"
});
Такой объект тоже будет обработан как промисоподобное значение.
Промис можно завершить только один раз
Это важно помнить в практическом коде.
Если промис уже завершён, последующие вызовы resolve() или reject() ничего не изменят.
const { promise, resolve, reject } = Promise.withResolvers();
promise.then((value) => {
console.log(value); // "first"
});
resolve("first");
resolve("second");
reject("third");
Сработает только первый вызов завершения.
Чем Promise.withResolvers() отличается от new Promise(...)
Это главное практическое сравнение.
Без Promise.withResolvers() код часто выглядит так:
let resolveFn;
let rejectFn;
const promise = new Promise((resolve, reject) => {
resolveFn = resolve;
rejectFn = reject;
});
С Promise.withResolvers() то же самое можно записать короче и понятнее:
const { promise, resolve, reject } = Promise.withResolvers();
Такой вариант удобнее читать, потому что он сразу показывает намерение: нам нужен промис и внешние функции для его завершения.
Promise.withResolvers() сам по себе не запускает асинхронную операцию
Это важное уточнение.
Метод только создаёт связку из промиса и функций управления. Асинхронная логика появляется не сама по себе, а в вашем коде.
const { promise, resolve } = Promise.withResolvers();
setTimeout(() => {
resolve("done");
}, 1000);
promise.then((value) => {
console.log(value); // "done"
});
Здесь асинхронность создаёт setTimeout, а не Promise.withResolvers().
Когда это полезно
Promise.withResolvers() особенно удобен, когда:
- нужно создать промис заранее, а завершить его позже
resolveиrejectдолжны быть доступны вне конструктора- вы хотите избежать ручного захвата переменных через
new Promise(...) - промис связан с внешним событием, таймером, очередью или подпиской
Пример:
function wait(ms) {
const { promise, resolve } = Promise.withResolvers();
setTimeout(() => {
resolve(`Прошло ${ms} мс`);
}, ms);
return promise;
}
wait(1000).then((message) => {
console.log(message); // "Прошло 1000 мс"
});
Такой подход хорошо подходит для вспомогательных абстракций, где промис нужно вернуть сразу, а завершить позже.
Частые ошибки
Думать, что Promise.withResolvers() возвращает сразу сам промис
const result = Promise.withResolvers();
console.log(result.promise);
Метод возвращает не один Promise, а объект с тремя свойствами: promise, resolve и reject.
Забывать брать promise из результата
const { resolve } = Promise.withResolvers();
resolve("ok");
Так можно вызвать resolve, но без promise вы не сможете нормально подписаться на результат через then() или catch().
Ожидать синхронное выполнение then()
const { promise, resolve } = Promise.withResolvers();
promise.then(() => {
console.log("done");
});
resolve();
console.log("after");
Сначала выведется after, и только потом done.
Пытаться изменить уже завершённый промис
const { promise, resolve, reject } = Promise.withResolvers();
resolve("first");
reject(new Error("boom"));
promise.then((value) => {
console.log(value); // "first"
});
После первого завершения остальные вызовы уже ничего не меняют.
Думать, что метод сам делает код асинхронным
const { promise } = Promise.withResolvers();
Сам по себе этот вызов просто создаёт объект и функции управления. Асинхронность появляется только тогда, когда вы связываете их с реальной операцией.
Быстрая памятка
Promise.withResolvers()вызывается уPromise- метод не принимает обязательных аргументов
- результатом является объект
{ promise, resolve, reject } resolve()успешно завершает связанный промисreject()завершает связанный промис с ошибкой- обработчики
then()иcatch()всё равно выполняются асинхронно - в
resolve()можно передать другой промис или thenable - промис можно завершить только один раз
- метод удобен как замена ручному шаблону с
new Promise(...)и внешними переменными
Коротко
Promise.withResolvers() в JavaScript нужен, когда хочется создать промис и сразу получить внешние функции resolve и reject без лишнего шаблонного кода. Главное, что стоит запомнить: метод возвращает объект с promise, resolve и reject, не запускает асинхронность сам по себе, ведёт себя как обычный Promise по правилам resolve и reject, и особенно полезен там, где промис создаётся в одном месте, а завершается позже в другом.