Как добавить таймаут к промису
Короткий ответ
Promise.race() завершается вместе с первым завершившимся промисом. Устройте гонку задачи с таймером, который завершается ошибкой:
function withTimeout(promise, ms) {
let timer;
const timeout = new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error(`Timed out after ${ms} ms`)), ms);
});
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
}
const delay = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
console.log(await withTimeout(delay(50, 'fast answer'), 200));
try {
await withTimeout(delay(500, 'slow answer'), 200);
} catch (error) {
console.log(error.message);
}Результат:
fast answer
Timed out after 200 msДля fetch
Для запросов передайте сигнал: тогда отменится сам запрос, а не только ожидание:
const response = await fetch('/api/report', { signal: AbortSignal.timeout(3000) });Частая ошибка
Таймаут только прекращает ожидание. Сама медленная операция продолжает работать в фоне, а её результат просто игнорируется:
const slow = new Promise((resolve) =>
setTimeout(() => {
console.log('the slow task still finished');
resolve();
}, 300),
);
await Promise.race([slow, new Promise((resolve) => setTimeout(resolve, 100))]);
console.log('stopped waiting');
await new Promise((resolve) => setTimeout(resolve, 300));Результат:
stopped waiting
the slow task still finishedФункции из этого ответа
- Promise.race — Возвращает результат первого завершившегося промиса — успешного или нет.
- fetch — Отправляет HTTP-запрос и возвращает промис ответа.