获取API请求超时?

时间:2017-10-26 05:23:17

标签: javascript ajax fetch-api

我有一个fetch-api POST请求:

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

我想知道这是什么默认超时?我们如何将其设置为特定值,如3秒或无限秒?

11 个答案:

答案 0 :(得分:65)

我非常喜欢gist使用Promise.race

https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614877-tableview方法

fetchWithTimeout.js

configurations.all {

    resolutionStrategy {
        force 'com.android.support:design:27.0.2'
        force 'com.android.support:support-v4:27.0.2'
        force 'com.android.support:appcompat-v7:27.0.2'
    }
}

main.js

android.enableAapt2=false

答案 1 :(得分:49)

它没有指定的默认值; the specification根本不讨论超时。

您可以为promises实现自己的超时包装:

// 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 :(得分:27)

使用中止语法,您将能够:

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);
})

请参阅MDN上的AbortController页面。

答案 3 :(得分:4)

fetch 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);
      }
    });
  }

答案 4 :(得分:2)

编辑:获取请求仍将在后台运行,很可能会在您的控制台中记录错误。

确实,Promise.race方法更好。

请参阅此链接以获取参考Promise.race()

Race意味着所有Promises将同时运行,并且只要其中一个promises返回一个值,竞争就会停止。 因此,只会返回一个值。 如果提取超时,您也可以传递一个函数来调用。

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;
   }
}

答案 5 :(得分:2)

基于Endless出色的answer,我创建了一个有用的实用程序功能。

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
        }
    });

希望有帮助。

答案 6 :(得分:2)

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

1)Firefox-90秒

在Firefox URL字段中输入about:config。查找与键network.http.connection-timeout

相对应的值

2)Chrome-300秒

Source

答案 7 :(得分:0)

您可以创建一个timeoutPromise包装器

class ExForm(forms.Form):
    a = forms.CharField(max_length=100, initial='Some value')
    b = forms.ChoiceField(choices=SOME_CHOICES)
    c = forms.ChoiceField(choices=SOME_CHOICES)

然后您可以包装任何承诺

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

它实际上不会取消基础连接,但可以使Promise超时。
Reference

答案 8 :(得分:0)

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

答案 9 :(得分:0)

使用c-promise2 lib具有超时的可取消获取可能看起来像这样(Live jsfiddle demo):

tibbletime

此代码作为npm软件包cp-fetch

答案 10 :(得分:0)

这是一个使用 NodeJS 的 SSCCE,它将在 1000 毫秒后超时:

const fetch = require('node-fetch');
const AbortController = require('abort-controller');

const controller = new AbortController();
const timeout = setTimeout(() => {
    controller.abort();
}, 1000); // will time out after 1000ms

fetch('https://www.yourexample.com', {
    signal: controller.signal,
    method: 'POST',
    body: formData,
    credentials: 'include'
}
)
.then(response => response.json())
.then(json => console.log(json))
.catch(err => {
    if(err.name === 'AbortError') {
        console.log('Timed out');
    }}
)
.finally( () => {
    clearTimeout(timeout);
});