← Назад к вопросам

Есть ли у Promise функционал для принудительного завершения через 5 секунд?

1.0 Junior🔥 141 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Promise timeout функционал

В стандартном JavaScript Promise нет встроенного функционала для принудительного завершения через определенное время. Однако существует несколько способов реализовать эту функциональность.

1. Использование Promise.race()

Это наиболее элегантный способ - гарантировать выполнение за определенное время:

// Функция для создания таймаута
function timeout(ms) {
  return new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
}

// Использование
const fetchWithTimeout = async () => {
  try {
    const result = await Promise.race([
      fetch('https://api.example.com/data'),
      timeout(5000) // 5 секунд
    ]);
    return result;
  } catch (error) {
    console.error('Операция прервана или истек таймаут:', error);
  }
};

2. AbortController (современный способ)

В современном JavaScript есть AbortController, который позволяет отменить fetch запрос:

const fetchWithTimeout = async (url, timeout = 5000) => {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, {
      signal: controller.signal
    });
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Запрос отменен по таймауту');
    }
    throw error;
  }
};

// Использование
await fetchWithTimeout('https://api.example.com/data', 5000);

3. Реализация helper функции

// Универсальная функция для любого Promise
function withTimeout(promise, ms) {
  return Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => {
        reject(new Error(`Operation timed out after ${ms}ms`));
      }, ms)
    )
  ]);
}

// Примеры использования
const slowFetch = fetch('https://api.example.com/data');

try {
  const result = await withTimeout(slowFetch, 5000);
  console.log('Успешно:', result);
} catch (error) {
  console.error('Ошибка или таймаут:', error.message);
}

4. Класс для более удобного использования

class TimeoutError extends Error {
  constructor(ms) {
    super(`Operation timed out after ${ms}ms`);
    this.name = 'TimeoutError';
  }
}

class PromiseWithTimeout {
  static race(promise, timeout) {
    return Promise.race([
      promise,
      new Promise((_, reject) =>
        setTimeout(() => reject(new TimeoutError(timeout)), timeout)
      )
    ]);
  }
  
  static async fetch(url, timeout = 5000) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    
    try {
      const response = await fetch(url, { signal: controller.signal });
      clearTimeout(timeoutId);
      return response;
    } catch (error) {
      clearTimeout(timeoutId);
      throw error;
    }
  }
}

// Использование
try {
  const response = await PromiseWithTimeout.fetch('/api/data', 5000);
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log('Таймаут истек');
  }
}

5. Практический пример в React

import { useState, useEffect } from 'react';

const DataFetcher = () => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 5000);

    const fetchData = async () => {
      try {
        const response = await fetch('/api/data', {
          signal: controller.signal
        });
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(
          err.name === 'AbortError' 
            ? 'Запрос превышил таймаут'
            : err.message
        );
      } finally {
        setLoading(false);
        clearTimeout(timeoutId);
      }
    };

    fetchData();

    return () => {
      controller.abort();
      clearTimeout(timeoutId);
    };
  }, []);

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;
  return <div>{JSON.stringify(data)}</div>;
};

Сравнение подходов

ПодходПлюсыМинусы
Promise.race()Простой, работает вездеНужно создавать отдельный Promise
AbortControllerСовременный, отменяет запросРаботает с fetch/XHR, не всегда поддерживается
setTimeout + rejectУниверсальныйБолее многословный код

Вывод

Нет встроенной функции в Promise, но есть несколько проверенных способов реализовать таймаут. Рекомендуется использовать AbortController для fetch запросов и Promise.race() для универсальных случаев.