如何在节点 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)中从基于承诺的函数中检索实际值,所以我通过生成器使用了 cohttps://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:调用一个可能会失败的函数,如果失败,稍等片刻再试。用承诺做所有这些。

这里有几个工具:

  1. setTimeout 的承诺版本...

function timeoutPromise(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

timeoutPromise(1000).then(() => {
    console.log('time out expired');
});

  1. 一个有时会失败的承诺返回虚拟函数...

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

请注意,您可以为最大尝试次数添加一个参数,在每次递归调用时递减该参数,然后如果该参数为零则不递归。另请注意,在递归调用中,您可能会选择延长等待时间。