Future
Future — ленивая (без состояния) асинхронная абстракция: описание того, как получить значение, а не уже-запущенная операция. В отличие от Promise, Future не запускается до первого вызова
.fork.
Что это / Зачем
Promise — eager: выполняется сразу при создании. Иногда нужно описать асинхронное вычисление декларативно и запустить позже (или несколько раз). Future:
- ленивый — без состояния, без кеша результата;
- является монадой (
of+chain= unit + bind); - описывает цепочку вычислений, которая исполняется при
fork(onSuccess, onError); - может выполняться многократно без побочных эффектов.
Идея пришла из FP (Haskell, Fantasy Land в JS, библиотека Fluture).
API / Синтаксис
// Минимальный Future: хранит executor, но не запускает его
class Future {
constructor(executor) { this.executor = executor; }
static of(value) { return new Future((s, _) => s(value)); }
fork(onSuccess, onError) { this.executor(onSuccess, onError); }
map(fn) {
return new Future((s, e) =>
this.fork((v) => s(fn(v)), e));
}
chain(fn) { // flatMap
return new Future((s, e) =>
this.fork((v) => fn(v).fork(s, e), e));
}
}
// Использование
const f = Future
.of(1)
.map((x) => x + 1)
.chain((x) => new Future((s) => setTimeout( => s(x * 10), 100)));
f.fork(console.log, console.error); // запуск!
// один и тот же future можно форкнуть несколько раз
f.fork(console.log, console.error);
Ключевые моменты
- Без
forkничего не происходит — это главное отличие от Promise. - Future — чистая абстракция, нет внутреннего состояния → нет кеша, нет однократного разрешения.
- Цепочка строится «вперёд», а исполнение разворачивается «назад» — fork идёт по цепочке к началу и стартует executor самого первого Future.
map(fn)— для трансформаций;chain(fn)— когдаfnсама возвращает Future.- Контракт монады:
Future.of(unit) +chain(bind) + ассоциативность. - В Promise/A+ thenable, в FP мире — Future/Task.
Подводные камни
- Future вычисляется столько раз, сколько раз вызвали
fork— если внутри HTTP, файл прочитается дважды. - Нет встроенной отмены — нужно делать самому через onCancel-колбэк.
- Преобразование Future → Promise теряет ленивость.
🎓 Источники
- 🎓 [Future. Asynchrony on Stateless Futures] · 2019-05-14 · YouTube
- Тезисы:
- Future ленивый и без состояния, в отличие от eager-Promise.
- Контракт монады:
of+chain. - Цепочка строится вперёд, исполнение разворачивается назад.
- Без
forkфайл не читается. Несколькоfork— несколько чтений. - Future ↔ Promise через адаптеры
futureify/promisify.
- Цитата:
«Future ленивый и без состояния. Promise eager и со состоянием. Это две разные модели одной и той же сущности — отложенного значения.»
- Тезисы: