我有一个fetch-api POST请求:

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

我想知道这个的默认超时时间是多少?我们如何将它设置为特定的值,比如3秒或不定秒?


当前回答

编辑1

正如注释中所指出的,原始答案中的代码即使在承诺被解析/拒绝之后也会继续运行计时器。

下面的代码修复了这个问题。

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

其他回答

如果您没有在代码中配置超时,它将是浏览器的默认请求超时。

1) Firefox - 90秒

在Firefox URL字段中输入about:config。找到key network.http.connection-timeout对应的值

2) Chrome - 300秒

基于无尽的回答,我创造了一个有用的效用函数。

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
        }
    });
  fetchTimeout (url,options,timeout=3000) {
    return new Promise( (resolve, reject) => {
      fetch(url, options)
      .then(resolve,reject)
      setTimeout(reject,timeout);
    })
  }

您可以创建一个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(...)  

它实际上不会取消底层连接,但允许您超时承诺。 参考

使用AbortController和setTimeout;

const abortController = new AbortController();

let timer: number | null = null;

fetch('/get', {
    signal: abortController.signal, // Content to abortController
})
    .then(res => {
        // response success
        console.log(res);

        if (timer) {
            clearTimeout(timer); // clear timer
        }
    })
    .catch(err => {
        if (err instanceof DOMException && err.name === 'AbortError') {
            // will return a DOMException
            return;
        }

        // other errors
    });

timer = setTimeout(() => {
    abortController.abort();
}, 1000 * 10); // Abort request in 10s.

这是@fatcherjs/middleware-aborter中的一个片段。

通过使用fatcher,可以很容易地中止取回请求。

import { aborter } from '@fatcherjs/middleware-aborter';
import { fatcher, isAbortError } from 'fatcher';

fatcher({
    url: '/bar/foo',
    middlewares: [
        aborter({
            timeout: 10 * 1000, // 10s
            onAbort: () => {
                console.log('Request is Aborted.');
            },
        }),
    ],
})
    .then(res => {
        // Request success in 10s
        console.log(res);
    })
    .catch(err => {
        if (isAbortError(err)) {
            //Run error when request aborted.
            console.error(err);
        }

        // Other errors.
    });