如何在节点 6 放弃之前使用 setTimeout 使基于承诺的函数执行几次(即 async/await 没有 javascript 规范)
How to make a promise based function to be executed a few times with setTimeout before giving up in node 6 (i.e. no javascript specs for async/await)
我需要在节点 6 环境(Azure Functions)中从基于承诺的函数中检索实际值,所以我通过生成器使用了 co
(https://www.npmjs.com/package/co)(而不是 async/await范式)来处理内在的承诺。
在最终放弃之前,我还需要使用 setTimeout
重试几次 co
/promise 函数。
我目前无法使以下代码按预期工作。我不确定问题出在哪里,但我不能 "yield from the promise returned by co
",所以最后在堆栈的递归级别传递的数组包含值 (1/0) 的承诺而不是实际值。
这是 "promise based function" 的包装器,由 try/catch 处理以确保我们实际上 总是 return 1 或 0。
const wannabeSyncFunc = () => {
console.log("outside co...");
return co(function *(){
console.log("inside co...");
try {
console.log("yielding...");
// promise that could be rejected hence try/catch
//
// I can not change this returned promise, so I must treat it
// as a promise that could potentially be rejected
let stuff = yield Promise.resolve();
console.log("stuff?", stuff);
console.log("returning 1");
return 1;
} catch (err) {
console.log("returning 0");
return 0;
}
console.log("after try/catch...");
});
}
这是 recursive/settimeout 函数,应该在放弃之前尝试几次。
const retryIntervalInMillis = 50;
const wannabeRecursiveFunc = (currTimes, attemptsArray) => {
return co(function *(){
console.log("Curr attemptsArray:", attemptsArray);
console.log("Curr attemptsArray[attemptsArray.length - 1]:", attemptsArray[attemptsArray.length - 1]);
console.log("Curr Promise.resolve(attemptsArray[attemptsArray.length - 1]):", Promise.resolve(attemptsArray[attemptsArray.length - 1]));
if (attemptsArray[attemptsArray.length - 1] == Promise.resolve(1)) {
console.log("Found the solution, returning straight away!")
return attemptsArray;
}
if (currTimes <= 0) {
console.log("Expired acquiring recursion");
return attemptsArray;
}
currTimes--;
const currValue = wannabeSyncFunc();
console.log(`First: currTimes: ${currTimes} currValue: ${currValue} curr attemptsArray: ${attemptsArray}`);
attemptsArray.push(currValue);
if (currValue === 1) {
return attemptsArray;
}
console.log(`Then: currTimes: ${currTimes} curr attemptsArray: ${attemptsArray}`);
return yield setTimeout(wannabeRecursiveFunc, currTimes*retryIntervalInMillis, currTimes, attemptsArray);
// return Promise.all(attemptsArray);
});
}
我试过用几种不同的方式调用它,例如:
const numberOfAttempts = 3;
let theArray = wannabeRecursiveFunc(numberOfAttempts, []);
console.log(">>>", theArray);
或者假设 wannabeRecursiveFunc
到 return 一个承诺,并且 .then
在承诺之后尝试打印 theArray
.
打印时我一直在数组中看到这些元素 Promise { 1 }
,但我希望看到 1 或 0,所以 我希望递归之前的那些检查能够按预期工作。目前这些检查不起作用,我想是因为我正在比较 Promise { 1 }
和 1
.
但是,我不确定这就是整个系统无法正常工作的原因,我什至不确定如何解决这个问题。我不确定是否需要 co
(即使在 node.js v6 环境中),以及如何使这个 promise/setTimeout 按预期工作。
我想我理解你的objective:调用一个可能会失败的函数,如果失败,稍等片刻再试。用承诺做所有这些。
这里有几个工具:
- setTimeout 的承诺版本...
function timeoutPromise(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
timeoutPromise(1000).then(() => {
console.log('time out expired');
});
- 一个有时会失败的承诺返回虚拟函数...
function fnThatMightFail() {
return new Promise((resolve, reject) => {
let fail = Math.random() < 0.40;
(fail)? reject('bad') : resolve('good');
});
}
fnThatMightFail().then(result => {
console.log(result);
}).catch(error => {
console.log(error);
});
然后,我认为这就是您正在寻找的递归思想。传入一个函数和尝试之间的等待时间,递归调用直到我们成功...
function fnThatMightFail() {
return new Promise((resolve, reject) => {
let fail = Math.random() < 0.40;
(fail)? reject('bad') : resolve('good');
});
}
function timeoutPromise(ms) {
return new Promise((resolve) => {
setTimeout(() => resolve(), ms);
});
}
function fnRetryer(fn, tries, wait) {
if (tries <= 0) return Promise.reject('bad');
console.log('attempting fn');
return fn().then(result => {
console.log(`success: ${result}`);
return result;
}).catch(error => {
console.log(`error: ${error}, retrying after ${wait}ms`);
return timeoutPromise(wait).then(result => {
console.log(`${wait}ms elapsed, recursing...`);
return fnRetryer(fn, tries-1, wait);
});
});
}
fnRetryer(fnThatMightFail, 5, 1000).then(result => {
console.log(`we tried (and maybe tried) and got ${result}`);
}).catch(error => {
console.log('we failed after 5 tries, waiting 1s in between each try');
});
请注意,您可以为最大尝试次数添加一个参数,在每次递归调用时递减该参数,然后如果该参数为零则不递归。另请注意,在递归调用中,您可能会选择延长等待时间。
我需要在节点 6 环境(Azure Functions)中从基于承诺的函数中检索实际值,所以我通过生成器使用了 co
(https://www.npmjs.com/package/co)(而不是 async/await范式)来处理内在的承诺。
在最终放弃之前,我还需要使用 setTimeout
重试几次 co
/promise 函数。
我目前无法使以下代码按预期工作。我不确定问题出在哪里,但我不能 "yield from the promise returned by co
",所以最后在堆栈的递归级别传递的数组包含值 (1/0) 的承诺而不是实际值。
这是 "promise based function" 的包装器,由 try/catch 处理以确保我们实际上 总是 return 1 或 0。
const wannabeSyncFunc = () => {
console.log("outside co...");
return co(function *(){
console.log("inside co...");
try {
console.log("yielding...");
// promise that could be rejected hence try/catch
//
// I can not change this returned promise, so I must treat it
// as a promise that could potentially be rejected
let stuff = yield Promise.resolve();
console.log("stuff?", stuff);
console.log("returning 1");
return 1;
} catch (err) {
console.log("returning 0");
return 0;
}
console.log("after try/catch...");
});
}
这是 recursive/settimeout 函数,应该在放弃之前尝试几次。
const retryIntervalInMillis = 50;
const wannabeRecursiveFunc = (currTimes, attemptsArray) => {
return co(function *(){
console.log("Curr attemptsArray:", attemptsArray);
console.log("Curr attemptsArray[attemptsArray.length - 1]:", attemptsArray[attemptsArray.length - 1]);
console.log("Curr Promise.resolve(attemptsArray[attemptsArray.length - 1]):", Promise.resolve(attemptsArray[attemptsArray.length - 1]));
if (attemptsArray[attemptsArray.length - 1] == Promise.resolve(1)) {
console.log("Found the solution, returning straight away!")
return attemptsArray;
}
if (currTimes <= 0) {
console.log("Expired acquiring recursion");
return attemptsArray;
}
currTimes--;
const currValue = wannabeSyncFunc();
console.log(`First: currTimes: ${currTimes} currValue: ${currValue} curr attemptsArray: ${attemptsArray}`);
attemptsArray.push(currValue);
if (currValue === 1) {
return attemptsArray;
}
console.log(`Then: currTimes: ${currTimes} curr attemptsArray: ${attemptsArray}`);
return yield setTimeout(wannabeRecursiveFunc, currTimes*retryIntervalInMillis, currTimes, attemptsArray);
// return Promise.all(attemptsArray);
});
}
我试过用几种不同的方式调用它,例如:
const numberOfAttempts = 3;
let theArray = wannabeRecursiveFunc(numberOfAttempts, []);
console.log(">>>", theArray);
或者假设 wannabeRecursiveFunc
到 return 一个承诺,并且 .then
在承诺之后尝试打印 theArray
.
打印时我一直在数组中看到这些元素 Promise { 1 }
,但我希望看到 1 或 0,所以 我希望递归之前的那些检查能够按预期工作。目前这些检查不起作用,我想是因为我正在比较 Promise { 1 }
和 1
.
但是,我不确定这就是整个系统无法正常工作的原因,我什至不确定如何解决这个问题。我不确定是否需要 co
(即使在 node.js v6 环境中),以及如何使这个 promise/setTimeout 按预期工作。
我想我理解你的objective:调用一个可能会失败的函数,如果失败,稍等片刻再试。用承诺做所有这些。
这里有几个工具:
- setTimeout 的承诺版本...
function timeoutPromise(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
timeoutPromise(1000).then(() => {
console.log('time out expired');
});
- 一个有时会失败的承诺返回虚拟函数...
function fnThatMightFail() {
return new Promise((resolve, reject) => {
let fail = Math.random() < 0.40;
(fail)? reject('bad') : resolve('good');
});
}
fnThatMightFail().then(result => {
console.log(result);
}).catch(error => {
console.log(error);
});
然后,我认为这就是您正在寻找的递归思想。传入一个函数和尝试之间的等待时间,递归调用直到我们成功...
function fnThatMightFail() {
return new Promise((resolve, reject) => {
let fail = Math.random() < 0.40;
(fail)? reject('bad') : resolve('good');
});
}
function timeoutPromise(ms) {
return new Promise((resolve) => {
setTimeout(() => resolve(), ms);
});
}
function fnRetryer(fn, tries, wait) {
if (tries <= 0) return Promise.reject('bad');
console.log('attempting fn');
return fn().then(result => {
console.log(`success: ${result}`);
return result;
}).catch(error => {
console.log(`error: ${error}, retrying after ${wait}ms`);
return timeoutPromise(wait).then(result => {
console.log(`${wait}ms elapsed, recursing...`);
return fnRetryer(fn, tries-1, wait);
});
});
}
fnRetryer(fnThatMightFail, 5, 1000).then(result => {
console.log(`we tried (and maybe tried) and got ${result}`);
}).catch(error => {
console.log('we failed after 5 tries, waiting 1s in between each try');
});
请注意,您可以为最大尝试次数添加一个参数,在每次递归调用时递减该参数,然后如果该参数为零则不递归。另请注意,在递归调用中,您可能会选择延长等待时间。