В веб-разработке при управлении асинхронными задачами, такими как извлечение данных и загрузка файлов, часто возникают ситуации, когда необходимо прервать операции. Интерфейс AbortSignal, появившийся в DOM в современных веб-браузерах, предоставляет возможность корректно прервать асинхронные операции.

Рассмотрим два малоизвестных статических метода AbortSignalAbortSignal.timeout() и AbortSignal.any(). Эти методы предоставляют мощные возможности для эффективного управления асинхронными задачами и реагирования на них. Они полностью поддерживаются всеми основными веб-браузерами.

AbortSignal.timeout()

Статический метод AbortSignal.timeout()  предлагает удобный способ создания AbortSignal, который автоматически выполняет прерывание по истечении заданного времени. Этот метод возвращает экземпляр AbortSignal, который прерывается с исключением TimeoutError DOMException, если указанное время истекает до завершения операции.

Он также прерывается с AbortError DOMException, если пользователь инициирует действие остановки, например нажатие кнопки остановки браузера.

const fetchFile = async (url, timeout) => {
try {
const response = await fetch(url, {
signal: AbortSignal.timeout(timeout) 👈👈👈
});
const file = await response.blob();
// Обработка файла
console.log("File fetched successfully:", file);
} catch (error) {
handleFetchError(error);
}
};

const handleFetchError = (error) => {
switch (error.name) {
case "TimeoutError":
console.error("The operation timed out.");
break;
case "AbortError":
console.error("The fetch operation was aborted.");
break;
default:
console.error(`An error occurred: ${error.message}`);
}
};

// Пример использования
const fileUrl = "https://path_to_large_file.mp4";
const fetchTimeout = 5_000; // 5 секунд

fetchFile(fileUrl, fetchTimeout);

Этот пример демонстрирует использование AbortSignal.timeout() для получения файла в пределах таймаута в 5 секунд. В зависимости от результата различают ошибки таймаута, прерывания, инициированные пользователем, и другие потенциальные ошибки.

AbortSignal.any()

Статический метод AbortSignal.any() позволяет объединить несколько экземпляров AbortSignal в один, что облегчает координацию действий по прерыванию. Он принимает iterable (итерируемый объект) сигналов прерывания и возвращает AbortSignal, который прерывает работу всякий раз, когда любой из входных сигналов прерывается. Причину прерывания следует искать в первом сигнале, вызвавшем прерывание.

const cancelDownloadBtn = document.querySelector('button');
const userCancelController = new AbortController();

cancelDownloadBtn.addEventListener("click", () => {
userCancelController.abort();
});

const timeoutDuration = 1_000 * 60 * 5; // 5 минут

// Создание комбинированного сигнала для обработки отмены и таймаута
const timeoutSignal = AbortSignal.timeout(timeoutDuration);
const combinedSignal = AbortSignal.any([
userCancelController.signal,
timeoutSignal,
]);

try {
const response = await fetch(someUrlToDownload, {
signal: combinedSignal 👈👈👈
});
const downloadedContent = await response.blob();
// Обработка загруженного содержимого
} catch (error) {
if (error.name === "AbortError") {
// Обработка отмены
} else if (error.name === "TimeoutError") {
// Обработка таймаута
} else {
// Обработка других ошибок (например, ошибок с сетью)
}
}

В этом примере AbortSignal.any() используется для создания комбинированного сигнала, который выполняет прерывание либо когда пользователь отменяет загрузку, либо по истечении таймаута в 5 минут, в зависимости от того, что произойдет раньше.

Его можно использовать с любым API, принимающим AbortSignal, например:

document.querySelector('button').addEventListener(
'click',
() => { },
{
// Отмена события после 4 секунд
signal: AbortSignal.timeout(4_000),
}
);

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Netanel Basal: Harnessing Control: Exploring JavaScript’s AbortSignal Timeout and Any Methods

Предыдущая статьяСоздание пользовательских метрик Prometheus в Golang и отправка оповещений в Slack с Grafana
Следующая статьяШаблоны рендеринга Next JS: полное руководство