Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как добавить таймаут к промису

Короткий ответ

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-запрос и возвращает промис ответа.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.