Lifecycle, Batch и Scheduling
Назначение
Эта страница объясняет, как Nrgy.js работает с cleanup, согласованными обновлениями и временем срабатывания реакций.
Scope
Scope владеет освобождаемыми ресурсами: effects, child scopes, atoms и пользовательскими teardown callbacks.
import { createScope } from '@nrgyjs/core';
const scope = createScope();
const count = scope.atom(0);
scope.effect(count, (value) => {
console.log(value);
});
scope.destroy();Почему scope важен:
- делает время жизни явным
- группирует реактивные ресурсы
- уменьшает риск утечек подписок
- естественно встраивается в lifecycle контроллеров
Что может собирать scope:
- subscriptions, возвращаемые
effect()илиsyncEffect() - atoms, созданные через
scope.atom() - child scopes, созданные через
scope.createScope() - произвольные destroyable или unsubscribable ресурсы, переданные через
scope.add() - пользовательские cleanup callbacks, зарегистрированные через
onDestroy
Когда scope уничтожается, его ресурсы уничтожаются или отписываются в одном месте. Это и есть основной механизм feature-level cleanup.
Destroy и Cleanup
В Nrgy.js cleanup является частью дизайна. Здесь cleanup означает освобождение ресурсов: subscriptions, timers, sockets, long-lived state и других объектов, которые не должны оставаться живыми после завершения owning feature.
Рекомендуемые практики:
- уничтожать контроллеры, когда завершается owning feature
- уничтожать atoms с большими данными, если они живут дольше локальных ссылок
- регистрировать внешние подписки, сокеты и таймеры в scope cleanup
- использовать
onDestroyдля освобождения ресурсов, а не для основной бизнес-логики
Cleanup особенно важен, когда:
- atom хранит большие объекты, кэши или бинарные данные
- фича создаёт timers, sockets или внешние subscriptions
- controller переживает один render, но не всё приложение
- state широко разделяется и может оставаться достижимым после ухода экрана
Очистка памяти для long-lived объектов остаётся ответственностью разработчика.
Batch
batch() откладывает выполнение реакций, пока не завершится группа обновлений.
import { atom, batch } from '@nrgyjs/core';
const firstName = atom('Ada');
const lastName = atom('Lovelace');
batch(() => {
firstName.set('Grace');
lastName.set('Hopper');
});batch() нужен, когда:
- несколько полей образуют единый логический переход состояния
- наблюдатели должны увидеть только финальное согласованное состояние
- серия write-операций иначе вызовет лишние реакции
Scheduling
Это один из ключевых выборов дизайна: эффекты в Nrgy.js не сводятся к немедленным синхронным колбэкам.
Практические следствия:
- концептуально Nrgy.js работает с двумя очередями: синхронные реакции и отложенные реакции
- обычный
effect()обычно работает отложенно syncEffect()доступен для синхронного наблюдения- batching естественно сочетается с отложенными реакциями
- тайминг реакций является частью API-контракта
- отложенные эффекты обычно запускаются после текущей синхронной работы, что с точки зрения пользователя похоже на microtask-поведение
Такая модель помогает избежать наблюдения промежуточных несогласованных состояний.
Почему эффекты могут вызываться не сразу:
- в одном синхронном flow может происходить несколько state writes
- отложенное выполнение позволяет рантайму увидеть финальные стабильные значения
- это уменьшает риск работы по промежуточным состояниям
- это снижает потребность в ручном batching во многих обычных кейсах
Ограничения и инварианты
Нужно держать в голове такие правила:
compute()должен оставаться чистым- записи в state должны жить в actions, effects или явных mutation points
- side effects должны жить в
effect()или actions контроллера, а не в чистых derivations - владение cleanup должно быть видно из кода, который создаёт ресурсы
syncEffect()- это opt-in инструмент, а не дефолтная модель реакции
Типичные ошибки:
- писать в atoms изнутри
compute() - прятать cleanup за неявным глобальным владением
- держать большой state после уничтожения owning feature
- смешивать derivation, mutation и I/O внутри одного reactive expression
Чеклист
- Стратегию cleanup надо описывать рядом с созданием ресурса.
- По умолчанию стоит предпочитать обычный
effect(). - Для multi-field updates нужно использовать
batch(). - Производную логику надо держать чистой, а workflow переносить в controllers.