我有一个fetch-api POST要求:
fetch(url, {
  method: 'POST',
  body: formData,
  credentials: 'include'
})
我想知道这个的默认超时时间是多少?我们如何将其设置为特定值,例如 3 秒或无限秒?
我有一个fetch-api POST要求:
fetch(url, {
  method: 'POST',
  body: formData,
  credentials: 'include'
})
我想知道这个的默认超时时间是多少?我们如何将其设置为特定值,例如 3 秒或无限秒?
使用Promise竞争解决方案将使请求挂起并仍然在后台消耗带宽,并在它仍在处理时降低最大允许并发请求。
而是使用AbortController来实际中止请求,这是一个示例
const controller = new AbortController()
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000)
fetch(url, { signal: controller.signal }).then(response => {
  // completed request before timeout fired
  // If you only wanted to timeout the request, not the response, add:
  // clearTimeout(timeoutId)
})
AbortController 也可以用于其他事情,不仅可以用于获取,还可以用于可读/可写流。更多较新的函数(特别是基于 Promise 的函数)将越来越多地使用它。NodeJS 也在其流/文件系统中实现了 AbortController。我知道网络蓝牙也在研究它。现在它也可以与 addEventListener 选项一起使用,并在信号结束时停止监听
如果您喜欢处理所有边缘情况的更干净的解决方案,请编辑此答案:https : //stackoverflow.com/a/57888548/1059828。
我真的很喜欢这个要点中使用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)
        )
    ]);
}
主文件
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
})
正如评论中所指出的,即使在Promise被解决/拒绝之后,原始答案中的代码也会继续运行计时器。
下面的代码解决了这个问题。
function timeout(ms, promise) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('TIMEOUT'))
    }, ms)
    promise
      .then(value => {
        clearTimeout(timer)
        resolve(value)
      })
      .catch(reason => {
        clearTimeout(timer)
        reject(reason)
      })
  })
}
它没有指定的默认值;该规范根本没有讨论超时。
通常,您可以为Promise实现自己的超时包装器:
// 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
基于 Endless 的出色回答,我创建了一个有用的实用程序功能。
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));
};
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
        }
    });
希望有帮助。
fetch API 中还没有超时支持。但是可以通过将其包装在Promise中来实现。
例如。
  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);
      }
    });
  }