Время ожидания запроса API-запроса?

У меня есть запрос fetch-api POST:

   fetch(url, {
      method: 'POST',
      body: formData,
      credentials: 'include'
    })

Я хочу знать, что такое тайм-аут по умолчанию для этого? и как мы можем установить его на определенное значение, например, 3 секунды или неопределенные секунды?

Ответ 1

Он не имеет заданного значения по умолчанию; спецификация не обсуждает тайм-ауты вообще.

Вы можете реализовать свою собственную оболочку тайм-аута для обещаний в целом:

// Rough implementation. Untested.
function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("timeout"))
    }, ms)
    promise.then(resolve, reject)
  })
}

timeout(1000, fetch('/hello')).then(function(response) {
  // process response
}).catch(function(error) {
  // might be a timeout error
})

Как описано в https://github.com/github/fetch/issues/175 Комментарий https://github.com/mislav

Ответ 2

Мне очень нравится чистый подход от этой сущности, используя Promise.race

fetchWithTimeout.js

export default function (url, options, timeout = 7000) {
    return Promise.race([
        fetch(url, options),
        new Promise((_, reject) =>
            setTimeout(() => reject(new Error('timeout')), timeout)
        )
    ]);
}

main.js

import fetch from './fetchWithTimeout'

// call as usual or with timeout as 3rd argument

fetch('http://google.com', options, 5000) // throw after max 5 seconds timeout error
.then((result) => {
    // handle result
})
.catch((e) => {
    // handle errors and timeout error
})

Ответ 3

Используя синтаксис прерывания, вы сможете сделать:

const controller = new AbortController();
const signal = controller.signal;

const fetchPromise = fetch(url, {signal});

// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000);


fetchPromise.then(response => {
  // completed request before timeout fired

  // If you only wanted to timeout the request, not the response, add:
  // clearTimeout(timeoutId);
})

Смотрите страницу AbortController на MDN.

Ответ 4

в API выборки пока нет поддержки тайм-аута. Но этого можно достичь, завернув его в обещание.

например

  function fetchWrapper(url, options, timeout) {
    return new Promise((resolve, reject) => {
      fetch(url, options).then(resolve, reject);

      if (timeout) {
        const e = new Error("Connection timed out");
        setTimeout(reject, timeout, e);
      }
    });
  }

Ответ 5

EDIT: запрос на выбор по-прежнему будет работать в фоновом режиме и, скорее всего, зарегистрирует ошибку в вашей консоли.

Действительно, подход Promise.race лучше.

См. Эту ссылку для справки Promise.race()

Раса означает, что все обещания будут выполняться одновременно, и гонка прекратится, как только одно из обещаний вернет значение. Поэтому возвращается только одно значение. Вы также можете передать функцию для вызова, если время ожидания выборки.

fetchWithTimeout(url, {
  method: 'POST',
  body: formData,
  credentials: 'include',
}, 5000, () => { /* do stuff here */ });

Если это заинтересует вас, возможная реализация будет:

function fetchWithTimeout(url, options, delay, onTimeout) {
   const timer = new Promise((resolve) => {
      setTimeout(resolve, delay, {
      timeout: true,
     });
   });
   return Promise.race([
      fetch(path, request),
      timer
   ]).then(response) {
      if (response.timeout) { 
        onTimeout();
      }
      return response;
   }
}

Ответ 6

Вы можете создать оболочку timeoutPromise

function timeoutPromise(timeout, err, promise) {
  return new Promise(function(resolve,reject) {
    promise.then(resolve,reject);
    setTimeout(reject.bind(null,err), timeout);
  });
}

Затем вы можете завернуть любое обещание

timeoutPromise(100, new Error('Timed Out!'), fetch(...))
  .then(...)
  .catch(...)  

Это на самом деле не отменит базовое соединение, но позволит вам тайм-аут обещания.
Ссылка

Ответ 7

  fetchTimeout (url,options,timeout=3000) {
    return new Promise( (resolve, reject) => {
      fetch(url, options)
      .then(resolve,reject)
      setTimeout(reject,timeout);
    })
  }

Ответ 8

Основываясь на превосходном ответе Enda, я создал полезную вспомогательную функцию.

const fetchTimeout = (url, ms, { signal, ...options } = {}) => {
    const controller = new AbortController();
    const promise = fetch(url, { signal: controller.signal, ...options });
    if (signal) signal.addEventListener("abort", () => controller.abort());
    const timeout = setTimeout(() => controller.abort(), ms);
    return promise.finally(() => clearTimeout(timeout));
};
  1. Если время ожидания истекло до извлечения ресурса, извлечение прекращается.
  2. Если ресурс выбирается до истечения времени ожидания, то время ожидания сбрасывается.
  3. Если входной сигнал прерывается, выборка прерывается, и время ожидания сбрасывается.
const controller = new AbortController();

document.querySelector("button.cancel").addEventListener("click", () => controller.abort());

fetchTimeout("example.json", 5000, { signal: controller.signal })
    .then(response => response.json())
    .then(console.log)
    .catch(error => {
        if (error.name === "AbortError") {
            // fetch aborted either due to timeout or due to user clicking the cancel button
        } else {
            // network error or json parsing error
        }
    });

Надеюсь, это поможет.