我正在使用浏览器的本机提取API进行网络请求。另外,我正在使用Whatwg-fetch Polyfill进行不支持的浏览器。
但是,如果请求失败,我需要重试。现在,我发现了这个NPM软件包Whatwg-fetch-Retry,但是他们尚未解释如何在文档中使用它。有人可以帮助我或建议我替代吗?
来自fetch docs:
fetch('/users')
.then(checkStatus)
.then(parseJSON)
.then(function(data) {
console.log('succeeded', data)
}).catch(function(error) {
console.log('request failed', error)
})
看到那个捕获吗?当获取失败时会触发,您可以在那里再次获取。看看Promise API。
实施示例:
function wait(delay){
return new Promise((resolve) => setTimeout(resolve, delay));
}
function fetchRetry(url, delay, tries, fetchOptions = {}) {
function onError(err){
triesLeft = tries - 1;
if(!triesLeft){
throw err;
}
return wait(delay).then(() => fetchRetry(url, delay, triesLeft, fetchOptions));
}
return fetch(url,fetchOptions).catch(onError);
}
编辑1:正如Golopot建议的,P-Retry是一个不错的选择。
编辑2:简化的示例代码。
我建议使用一些库进行承诺重试,例如p-retry。
示例:
const pRetry = require('p-retry')
const fetch = require('node-fetch')
async function fetchPage () {
const response = await fetch('https://stackoverflow.com')
// Abort retrying if the resource doesn't exist
if (response.status === 404) {
throw new pRetry.AbortError(response.statusText)
}
return response.blob()
}
;(async () => {
console.log(await pRetry(fetchPage, {retries: 5}))
})()
我不喜欢递归,除非确实有必要。管理爆炸数量的依赖项也是一个问题。这是打字稿中的另一种选择。这很容易翻译成JavaScript。
interface retryPromiseOptions<T> {
retryCatchIf?:(response:T) => boolean,
retryIf?:(response:T) => boolean,
retries?:number
}
function retryPromise<T>(promise:() => Promise<T>, options:retryPromiseOptions<T>) {
const { retryIf = (_:T) => false, retryCatchIf= (_:T) => true, retries = 1} = options
let _promise = promise();
for (var i = 1; i < retries; i++)
_promise = _promise.catch((value) => retryCatchIf(value) ? promise() : Promise.reject(value))
.then((value) => retryIf(value) ? promise() : Promise.reject(value));
return _promise;
}
并以这种方式使用...
retryPromise(() => fetch(url),{
retryIf: (response:Response) => true, // you could check before trying again
retries: 5
}).then( ... my favorite things ... )
我为浏览器上的获取API写了这篇文章。这没有在500上发出拒绝。我没有实施等待。但是,更重要的是,该代码显示了如何使用构图与承诺避免递归的承诺。
JavaScript版本:
function retryPromise(promise, options) {
const { retryIf, retryCatchIf, retries } = { retryIf: () => false, retryCatchIf: () => true, retries: 1, ...options};
let _promise = promise();
for (var i = 1; i < retries; i++)
_promise = _promise.catch((value) => retryCatchIf(value) ? promise() : Promise.reject(value))
.then((value) => retryIf(value) ? promise() : Promise.reject(value));
return _promise;
}
JavaScript用法:
retryPromise(() => fetch(url),{
retryIf: (response) => true, // you could check before trying again
retries: 5
}).then( ... my favorite things ... )
编辑:添加了JS版本,添加了retrycatchif,修复了循环启动。
一个人可以轻松地将fetch(...)
包装在循环中,并且catch
潜在错误(获取仅拒绝网络错误和类似的返回承诺):
const RETRY_COUNT = 5;
async function fetchRetry(...args) {
let count = RETRY_COUNT;
while(count > 0) {
try {
return await fetch(...args);
} catch(error) {
// logging ?
}
// logging / waiting?
count -= 1;
}
throw new Error(`Too many retries`);
}
使用Jonas Wilms和Isidrock答案并添加打字稿类型:
const MAX_NB_RETRY = 5;
const RETRY_DELAY_MS = 200;
export default async function fetchRetry(input: RequestInfo | URL, init?: RequestInit | undefined) {
let retryLeft = MAX_NB_RETRY;
while (retryLeft > 0){
try {
return await fetch(input, init);
}
catch (err) {
await sleep(RETRY_DELAY_MS)
}
finally {
retryLeft -= 1;
}
}
throw new Error(`Too many retries`);
}
function sleep(delay: number){
return new Promise((resolve) => setTimeout(resolve, delay));
}