我已经看到了一些关于重试Promise的问题,但是我要做的事情略有不同,因为我想管理重试/拒绝承诺有条件地直到达到最大重试次数。
举一个简单的例子,假设我们在XMLHttpRequest
周围包裹一个承诺。当请求加载状态为...
200
:解决承诺299
:立即重试399
:立即拒绝499
:从服务器获取内容,然后重试请注意,此处有一个范围可以在重试之前执行异步行为。
我一直在研究的解决方案涉及两个Promise。
回到我提到的例子......
XmlHttpRequest
,解析状态200
并拒绝其他。我认为我正朝着正确的方向前进,但似乎无法找到具体的解决方案。我正在寻找为这种有条件的重试承诺创建通用包装器。'
修改
这是一个正在进行的解决方案:
async function tryAtMost(maxAttempts, asyncCall, handleError)
{
for (let i = 0; i < maxAttempts; i++)
{
try
{
return await asyncCall();
}
catch (error)
{
const nextAction = await handleError(error); // await some async request (if available) before proceeding
const actionError = new Error(nextAction.error);
switch (nextAction.type)
{
case ACTIONS.ABORT:
throw actionError;
case ACTIONS.RETRY:
if (i === maxAttempts - 1) { throw actionError; }
else { continue; }
}
}
}
}
答案 0 :(得分:2)
有几种方法可以做到这一点,正如另一篇文章所示。我个人认为不必使用类。我会使用类似
之类的东西来接近它async function fetchWithRetries(theURL, remainingRetries = 5) {
const response = await fetch(theURL);
switch (response.status) {
case 200:
return await response.json(); // or whatever you need
case 299:
if (remainingRetries === 0) {
throw new Error();
}
return await fetchWithRetries(theURL, remainingRetries - 1);
case 399:
throw new Error();
case 499:
if (remainingRetries === 0) {
throw new Error();
}
const otherData = await fetchOtherData();
return await fetchWithRetries(theURL, remainingRetries - 1);
default:
// TODO: You didn't specify other codes?
}
}
答案 1 :(得分:1)
我只想创建一个返回async
函数的类(返回Promise
)。
Class
实例会跟踪attempts
。async
函数尝试获取x次的内容,等于maxAttempts
的数量。maxAttempts
。const rp = require('request-promise-native')
class RetryableFetch {
constructor({ url, maxAttempts = 3 }) {
this.url = url
this.maxAttempts = maxAttempts
this.attempts = 0
return this.generateRequest()
}
async generateRequest() {
for (let i = 0; i < this.maxAttempts; i++) {
try {
return await rp(this.url)
} catch(err) {
switch (err.statusCode) {
// Add more cases here as you see fit.
case 399:
throw err
break;
default:
if (++this.attempts === this.maxAttempts) throw err
}
}
}
}
}
new RetryableFetch({
url: 'https://www.google.com'
})
.then(result => {
console.log(result)
})
.catch(err => {
console.error(err)
})
如果您希望在浏览器中使用rp
,则可以将<body>
<form action="physical_server_check_list_saved.php" method="post">
<table width="800" align="left">
<th width="800" align="left" colspan="2" bgcolor="#D3D3D3">SERVER INFORMATION</th>
<tr>
<td width="200" align="left">Server name:</td>
<td width="600" align="left"><input type="text" size="100" name="servername"></td
/tr>
tr>
<td width="200" align="left">Contact:</td>
<td width="600" align="left"><input type="text" size="100" name="contact"></td
/tr>
<tr>
<td width="800" align="left" colspan="2">
<input type="submit" value="submit">
</td>
</tr>
</table>
</form>
</body>
替换为<tr>
<td width="200" align="left">Server name:</td>
<td width="600" align="left">
<?php
$servername = $_POST['servername'];
echo $servername;
?>
</td>
</tr>
<tr>
<td width="200" align="left">Contact:</td>>
<td width="600" align="left">
<?php
$contact = $_POST['contact'];
echo $contact;
?>
</td>
</tr>
,因为它们都使用基于Promise的API。
答案 2 :(得分:1)
基于您的评论:
我正在寻找为这种“有条件”重试承诺创建通用包装器。
这是一个更通用的包装器:
Promise
。
// Class Retryable
class Retryable {
constructor({ promise, maxAttempts = 1, attemptRetry }) {
this.promise = promise
this.maxAttempts = maxAttempts
this.attemptRetry = attemptRetry
this.attempts = 0
}
generateTry() {
console.info('generating request')
return this.promise().catch(err => {
if (++this.attempts === this.maxAttempts) throw err
return this.attemptRetry(err, () => this.generateTry() , () => {
throw err
})
})
}
}
// Usage
const retryable = new Retryable({
maxAttempts: 4,
promise: () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject({ status: 500 })
// If you `resolve` here instead you will trigger `.then()`
}, 200)
})
},
attemptRetry: function(err, yes, no) {
switch (err.status) {
case 500:
return yes()
break;
default:
return no()
}
}
})
retryable.generateTry().then(result => {
console.log(result)
}).catch(err => {
console.error(err)
})