Atomico — современная библиотека для построения веб-компонентов на JavaScript с реактивной архитектурой. Одной из важных особенностей работы с асинхронными операциями является корректное управление запросами и возможность их отмены, что повышает производительность и предотвращает утечки памяти.
В Atomico асинхронные операции обычно инициируются внутри
эффектов (useEffect) или реактивных
сигналов (useSignal). Основной принцип: эффект должен быть
чистым и корректно завершать предыдущие асинхронные операции при
повторном вызове.
import { c, useEffect, useSignal } from "atomico";
function fetchData(url) {
return fetch(url).then(res => res.json());
}
function Component() {
const data = useSignal(null);
useEffect(async (host) => {
const result = await fetchData("/api/items");
data.value = result;
});
return <host>{data.value && JSON.stringify(data.value)}</host>;
}
export default c(Component);
В этом примере useEffect запускает асинхронный запрос.
Однако, если компонент будет размонтирован или URL изменится, предыдущий
запрос останется активным, что может привести к нежелательным
эффектам.
AbortController для отмены запросовДля управления жизненным циклом асинхронных запросов применяют AbortController. Он позволяет отменять fetch-запросы при необходимости.
useEffect((host) => {
const controller = new AbortController();
fetch("/api/items", { signal: controller.signal })
.then(res => res.json())
.then(result => {
data.value = result;
})
.catch(err => {
if (err.name === "AbortError") return;
console.error(err);
});
return () => controller.abort();
}, []);
Ключевые моменты:
AbortController для каждого
запроса.signal в fetch.cleanup эффекта вызывается
controller.abort(), чтобы отменить запрос при
размонтировании компонента или повторном запуске эффекта.err.name === "AbortError".Если эффект зависит от реактивных сигналов, нужно отменять предыдущий запрос перед запуском нового:
useEffect((host) => {
const controller = new AbortController();
fetch(`/api/items?query=${query.value}`, { signal: controller.signal })
.then(res => res.json())
.then(result => data.value = result)
.catch(err => {
if (err.name === "AbortError") return;
console.error(err);
});
return () => controller.abort();
}, [query]);
query старый запрос
отменяется.useSignal для реактивного управленияСигналы в Atomico позволяют хранить состояние запроса и управлять его статусом:
const status = useSignal("idle"); // idle | loading | success | error
useEffect((host) => {
const controller = new AbortController();
status.value = "loading";
fetch("/api/items", { signal: controller.signal })
.then(res => res.json())
.then(result => {
data.value = result;
status.value = "success";
})
.catch(err => {
if (err.name === "AbortError") return;
status.value = "error";
console.error(err);
});
return () => controller.abort();
}, []);
Преимущества такого подхода:
При параллельных запросах можно хранить массив
AbortController для массовой отмены:
const controllers = useSignal([]);
useEffect((host) => {
const controller = new AbortController();
controllers.value.push(controller);
fetch("/api/items", { signal: controller.signal })
.then(res => res.json())
.then(result => data.value = result)
.catch(err => {
if (err.name === "AbortError") return;
console.error(err);
});
return () => {
controllers.value.forEach(c => c.abort());
controllers.value = [];
};
}, []);
Такой подход позволяет контролировать сразу несколько асинхронных операций и корректно завершать их при размонтировании компонента или изменении зависимостей.
Для удобства можно вынести логику запроса и отмены в кастомный хук:
function useFetch(url) {
const data = useSignal(null);
const status = useSignal("idle");
useEffect(() => {
const controller = new AbortController();
status.value = "loading";
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(result => {
data.value = result;
status.value = "success";
})
.catch(err => {
if (err.name === "AbortError") return;
status.value = "error";
console.error(err);
});
return () => controller.abort();
}, [url]);
return { data, status };
}
Использование хука упрощает повторное применение логики отмены запросов в разных компонентах и делает код более чистым и читаемым.
AbortError, чтобы не нарушить логику обработки других
ошибок.useEffect; необходимо использовать
cleanup функцию для контроля отмены.abort.Отмена запросов в Atomico становится естественной частью архитектуры компонентов, обеспечивая реактивность, предсказуемость состояния и защиту от побочных эффектов. Такой подход упрощает работу с сетевыми операциями и повышает устойчивость приложений к изменению состояния и быстрым интерактивным действиям пользователя.