Отмена эффектов
Отмена эффектов — важный механизм контроля асинхронных операций в конечных автоматах. lite-fsm предоставляет встроенные возможности для эффективного управления отменой эффектов при смене состояний.
Проблема асинхронных эффектов
В приложениях, использующих асинхронные операции (HTTP-запросы, таймеры, загрузка данных), могут возникать случаи, когда:
- Пользователь переходит на другую страницу до завершения запроса
- Новый запрос инициируется до завершения предыдущего
- Состояние автомата меняется, делая результат асинхронной операции неактуальным
В таких случаях необходим механизм отмены эффектов.
Автоматическая отмена при смене состояния
По умолчанию, при смене состояния автомата эффекты не отменяются автоматически. Отмена эффектов происходит только при использовании опции type: "latest" в создании эффекта.
Важно понимать, что при отмене эффекта сам код уже запущенного эффекта продолжает выполняться, но игнорируются transition-вызовы внутри этого эффекта. То есть мы просто игнорируем результаты работы эффектов, но не прерываем их выполнение:
export const player = createMachine({
config: {
IDLE: {
CHANGE_TRACK: "LOAD_TRACK_DATA",
},
LOAD_TRACK_DATA: {
LOAD_TRACK_DATA_STARTED: "LOAD_TRACK_DATA_PENDING",
},
LOAD_TRACK_DATA_PENDING: {
LOAD_TRACK_DATA_RESOLVE: "SELECT_STREAM_PENDING",
CHANGE_TRACK: "LOAD_TRACK_DATA", // Переход сюда НЕ отменит текущие эффекты по умолчанию
},
SELECT_STREAM_PENDING: {
SELECT_STREAM_RESOLVE: "SET_STREAM_PENDING",
},
SET_STREAM_PENDING: {},
},
initialState: "IDLE",
initialContext,
reducer: (s, action, { nextState }) => {
s.state = nextState;
return s;
},
effects: {
LOAD_TRACK_DATA: ({ transition }) => {
transition({
type: "LOAD_TRACK_DATA_STARTED",
});
},
LOAD_TRACK_DATA_PENDING: createEffect({
type: "latest", // Использование опции "latest" включает автоматическую отмену эффекта
effect: async ({ condition, transition }) => {
// Здесь код продолжит выполняться даже после отмены,
// но вызовы transition будут игнорироваться
await someAsyncOperation();
transition({
type: "LOAD_TRACK_DATA_RESOLVE", // Этот вызов будет проигнорирован, если эффект отменен
});
},
}),
},
});В этом примере, если автомат находится в состоянии LOAD_TRACK_DATA_PENDING и приходит событие CHANGE_TRACK, эффект будет отменен только потому, что мы указали type: "latest". Без указания этого параметра результаты всех эффектов будут обрабатываться независимо от смены состояния.
Типы эффектов и стратегии отмены
lite-fsm предоставляет два основных типа эффектов с разными стратегиями отмены:
1. Тип “latest”
Выполняется только последний вызов, предыдущие отменяются (transition-вызовы игнорируются):
const searchEffect = createEffect({
type: "latest", // необходимо явно указывать для активации отмены эффектов
effect: async ({ transition }, { query }) => {
const results = await api.search(query);
transition({ type: "SEARCH_SUCCESS", payload: { results } });
},
});2. Тип “every”
Выполняются все вызовы, без отмены (используется по умолчанию):
const logEffect = createEffect({
type: "every", // можно не указывать, так как это значение по умолчанию
effect: async ({ services }, { event }) => {
// Логирует каждое событие, без отмены
await services.analytics.logEvent(event);
},
});