在JavaScript中,我有一个对象数组要执行的一些任务。我使用for
的{{1}}循环遍历此数组,调用函数await
并返回doOneTask
。
只要Promise
中的代码按预期工作,效果就很好。但是,这些事情经常失败。再次尝试几乎总是有用。因此,我想在JavaScript代码中实现自动重试的过程。
我的想法是一个递归函数:如果失败,doOneTask
会自行调用直到承诺最终解决为止。
我的代码如下:
doOneTask
(在现实生活中,var tasks = [{label: 'task0'},{label: 'task1'},{label: 'task2'}];
async function mainFunction() {
for(let k = 0; k < tasks.length; k++) {
await doOneTask(tasks[k]);
console.log("doOneTask done for index " + k);
}
console.log("End reached!");
}
function doOneTask(task) {
return new Promise(async function (resolve,reject) {
console.log("Starting with: " + task.label);
let checkIfDoeSomeStuffWorked = await doSomeAsyncStuff();
if(checkIfDoeSomeStuffWorked == false) {
console.log(task.label + ": FAILED");
return doOneTask(task);
}
else {
console.log(task.label + ": SUCCESS");
resolve(true);
}
});
}
function doSomeAsyncStuff() {
return new Promise(function (resolve,reject) {
var myRandom = Math.random();
if(myRandom < 0.3) {
resolve(true);
}
else {
resolve(false);
}
});
}
mainFunction();
是一个后端调用,通常会失败。doSomeAsyncStuff
部分仅用于演示。实际上,在停止脚本之前,我还限制了试用次数。)
但是,它不起作用。如果失败,脚本将在到达random()
控制台日志后停止。我从不返回循环,循环中的下一个项目也从不执行。
答案 0 :(得分:1)
您没有使用q
库依赖项。 async
函数始终返回Promise,因此您可以简化代码-
async function doOneTask (task) {
const result = await doSomeAsyncStuff()
if (result === false) {
console.log(`${task} failed`)
return doOneTask(task)
}
else {
console.log(`${task} passed`)
return true
}
}
您的伪造函数doSomeAsyncStuff
也可以清除-
async function doSomeAsyncStuff () {
return Math.random() < 0.3
}
但是让我们添加1秒的假延迟,以便我们可以显示100%正常工作-
async function doSomeAsyncStuff () {
return new Promise(resolve =>
setTimeout(resolve, 1000, Math.random() < 0.3)
)
}
最后,您的main
函数使用了非常古老的循环约定。在使用现代JavaScript时,您不妨使用for-of
语法-
async function main (tasks = []) {
for (const t of tasks) {
await doOneTask(t)
}
return "done"
}
最后我们运行程序-
const tasks =
[ 'task0', 'task1', 'task2' ]
main(tasks).then(console.log, console.error)
// task0 failed
// task0 passed
// task1 failed
// task1 failed
// task1 passed
// task2 passed
// done
展开以下代码段,以在您自己的浏览器中验证结果-
async function doOneTask (task) {
const result = await doSomeAsyncStuff()
if (result === false) {
console.log(`${task} failed`)
return doOneTask(task)
}
else {
console.log(`${task} passed`)
return true
}
}
async function doSomeAsyncStuff () {
return new Promise(resolve =>
setTimeout(resolve, 1000, Math.random() < 0.3)
)
}
async function main (tasks = []) {
for (const t of tasks) {
await doOneTask(t)
}
return "done"
}
const tasks =
[ 'task0', 'task1', 'task2' ]
main(tasks).then(console.log, console.error)
// task0 failed
// task0 passed
// task1 failed
// task1 failed
// task1 passed
// task2 passed
// done
答案 1 :(得分:0)
完成问题之后,但在发布之前,我想到了一些事情:在上面的设置中,当我终于成功时,我并没有解析完全相同的promise对象,但是对于每个函数调用一个新的promise对象生成。我的解决方案/解决方法非常简单:使用q
Promise库,将Promise从一个函数调用传递到下一个函数调用:
var q = require('q');
async function doOneTask(task,promiseObj) {
if(!promiseObj) {
var promiseObj = q.defer();
}
console.log("Starting with: " + task.label);
let checkIfDoeSomeStuffWorked = await doSomeAsyncStuff();
if(checkIfDoeSomeStuffWorked == false) {
console.log(task.label + ": FAILED");
return doOneTask(task,promiseObj);
}
else {
console.log(task.label + ": SUCCESS");
promiseObj.resolve(true);
}
return promiseObj.promise;
}
这样,我们确保在第20次执行后的最终事件中解决在promise
的第一次调用中生成的同一doOneTask
对象。