Deferred
Deferred — объект, символизирующий будущее значение, у которого
resolve/rejectвыставлены как открытые методы наружу. Исторический предшественникPromise; сегодня прямой аналог —Promise.withResolvers.
Что это / Зачем
В эру до ES2015 (jQuery Deferred, Q.defer, когда промисов в языке не было), нужно было получить объект, у которого resolve/reject доступны снаружи, чтобы передать его в callback I/O. Промис «прячет» resolve/reject внутри executor'а — Deferred их «торчит наружу».
Сегодня тот же кейс решается через Promise.withResolvers (ES2024). Но Deferred-паттерн как идея остаётся полезным: он удобен в сценариях, когда промис создаётся в одном месте, а разрешается совсем в другом (контроллеры событий, очереди, FSM).
API / Синтаксис
// Минимальный Deferred
const defer = () => {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
// ES2024 — встроенный аналог
const { promise, resolve, reject } = Promise.withResolvers;
// Использование: разрешение из внешнего обработчика
const d = defer;
socket.once('message', (msg) => d.resolve(msg));
socket.once('error', (err) => d.reject(err));
const data = await d.promise;
Ключевые моменты
- Deferred выставляет три состояния:
pending,resolved,rejected. - В отличие от наивного объекта-обещания, нужен флаг
resolved, чтобы поздняя подписка тоже сработала (иначе подписка после разрешения «теряется»). - Из идеи Deferred выросли Promises.
- Не называйте свои методы
then/catchв обычных бизнес-объектах —await objнечаянно вызовет вашthenи зависнет. - Современная альтернатива —
Promise.withResolvers. Сторонний жанр — наследовать Deferred от EventEmitter (done/fail/on('progress')).
Подводные камни
- Поздняя подписка на наивный Deferred (без флага resolved) пропустит уже произошедшее событие.
- Один Deferred = одна операция. Цепочку из дифферов строить неудобно — этим занимаются полноценные Promise.
- Утечка resolve/reject в произвольный код — антипаттерн, если только не нужно явно (мост между EventEmitter и Promise).
🎓 Источники
- 🎓 [Deferred. Асинхронность на диферах с состоянием] · 2019-05-14 · YouTube
- Тезисы:
- Diferred — это объект, символизирующий будущее значение, с
done/fail/resolve/rejectнаружу. - Без флага
resolvedпоздняя подписка не сработает. - Из дифферов исторически развились Promise.
- Удобно реализовать Deferred поверх EventEmitter и сделать конвертер в Promise.
- Diferred — это объект, символизирующий будущее значение, с
- Цитата:
«Диффер не дружит с асинхронностью без флага resolved — поздняя подписка просто не срабатывает.»
- Тезисы:
- ⚡ [Promise.withResolvers VS new Promise] · 2025-12-21 · YouTube
- Тезис: современный Deferred =
Promise.withResolvers. См. Promise.withResolvers.
- Тезис: современный Deferred =