Управление памятью
Sagun автоматически управляет памятью, очищая операции и сервисы, когда они больше не нужны. Понимание этого механизма поможет оптимизировать производительность приложения.
Принцип работы
Подсчёт потребителей операций
Каждая операция в Sagun отслеживает своих потребителей (consumers). Потребителем операции становится:
- Компонент, который вызвал
useOperationс этой операцией - Се рвис, метод которого создал операцию через
@operation
Когда последний потребитель отписывается от операции, она автоматически уничтожается и удаляется из Redux store.
┌─────────────────────────────────────────────────────────────┐
│ Redux Store │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ asyncOperations │ │
│ │ ├── "UserService/fetchUser" (consumers: 2) │ │
│ │ ├── "OrderService/getOrders" (consumers: 1) │ │
│ │ └── "fetch-products" (consumers: 0) ← удаляется │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Жизненный цикл сервисов
Сервисы имеют явный жизненный цикл, управляемый через run() и destroy():
- Создание — сервис создаётся через
di.createService() - Инициализация —
useServiceвызываетrun() - Работа — сервис обрабатывает запросы, подписываясь на операции при их вызове
- Очистка — при unmount
useServiceвызываетdestroy(), отписываясь от операций
function ProductPage() {
const di = useDI();
const service = di.createService(ProductService);
di.registerService(service);
// При монтировании: service.run()
// При размонтировании: service.destroy()
const { operationId } = useService(service);
return (...);
}
Рекомендации по оптимизации
Регистрируйте сервисы близко к месту использования
Чем ближе сервис зарегистрирован к компонентам, которые его используют, тем эффективнее работает очистка памяти.
// ❌ Плохо: сервис страницы зарегистрирован в корне приложения
function App() {
const di = useDI();
const productService = di.createService(ProductService);
di.registerService(productService);
return <Router>...</Router>;
}// ✅ Хорошо: сервис страницы зарегистрирован на уровне страницы
function ProductPage() {
const di = useDI();
const productService = di.createService(ProductService);
di.registerService(productService);
return <ProductList />;
}
При втором подходе:
- Сервис создаётся только когда пользователь заходит на страницу
- При уходе со страницы сервис уничтожается вместе со всеми операциями
- Память освобождается автоматически
Используйте один useSaga на компонент
Каждый вызов useSaga создаёт отдельную операцию. Объединяйте связанные загрузки в одну сагу:
// ❌ Плохо: три отдельные операции
function Dashboard() {
useSaga({ id: 'user', onLoad: fetchUser });
useSaga({ id: 'orders', onLoad: fetchOrders });
useSaga({ id: 'stats', onLoad: fetchStats });
return (...);
}
// ✅ Хорошо: одна операция с параллельной загрузкой
function Dashboard() {
useSaga({
id: 'dashboard-data',
onLoad: function* () {
yield* all([
call(fetchUser),
call(fetchOrders),
call(fetchStats)
]);
}
});
return (...);
}
Очистка в onDispose
Если сага выполняет побочные эффекты (подписки, таймеры), очищайте их в onDispose:
useSaga({
id: 'websocket',
onLoad: function* () {
const socket = yield* call(connectWebSocket);
// Сохраняем ссылку для очистки
return socket;
},
onDispose: function* () {
// Вызывается при unmount или смене аргументов
yield* call(disconnectWebSocket);
}
});
См. также
- Сервисы — жизненный цикл сервисов
- Операции — как работают операции
- useService — автоматическое управление жизненным циклом
- useSaga — загрузка данных с очисткой