将setTimeout与递归承诺一起使用

时间:2018-01-19 09:00:02

标签: node.js promise

我有以下代码等待事务在以太坊区块链上挖掘。

function waitForMinedTransaction(txHash, tries = 1) {
  return new Promise(function(resolve, reject) {
    web3.eth.getTransactionReceipt(txHash, function(err, res) {
      if (err) reject(err)
      if (res) resolve(res)

      // nothing yet (retry in 10 sec..)
      console.log(`Attempt #${ tries }...`)
      if (tries > 60) reject("max_tries_exceeded")
      setTimeout(function() { return waitForMinedTransaction(txHash, tries + 1) }, 10000)
    })
  })
}

问题是当交易被挖掘时(例如在10次尝试之后),它永远不会被解决。我确定这与setTimeout和承诺链(其中承诺是return而不是resolve / reject当前承诺有关)但是需要一些关于修复它的指示。

1 个答案:

答案 0 :(得分:7)

我建议将链接逻辑嵌入到 promise构造函数回调中。

还要确保在解析或拒绝时退出该函数以避免执行其余代码。所以在调用returnresolve之前放一个reject,而不是返回值有任何意义,但只是为了确保函数代码的其余部分没有执行:

function waitForMinedTransaction(txHash) {
    return new Promise(function(resolve, reject) {
        (function attempt(triesLeft) {
            web3.eth.getTransactionReceipt(txHash, function(err, res) {
                if (err) return reject(err);
                if (res) return resolve(res);
                if (!triesLeft) return reject("max_tries_exceeded");
                console.log(`No result. Attempts left: #${ triesLeft }...`);
                setTimeout(attempt.bind(null, triesLeft-1), 10000);
            });
        })(60); // number of retries if first time fails
    });
}

如果您希望链中有新的承诺(就像您尝试过的那样),那么诀窍就是用链式承诺解决,即使用链式调用的返回值:

function waitForMinedTransaction(txHash, triesLeft = 60) {
    return new Promise(function(resolve, reject) {
        getTransactionReceipt(txHash, function(err, res) {
            if (err) return reject(err);
            if (res) return resolve(res);
            console.log(`No result. Attempts left: #${ triesLeft }...`);
            if (!triesLeft) return reject("max_tries_exceeded");
            setTimeout(_ => {
                resolve(waitForMinedTransaction(txHash, triesLeft-1));
            }, 10000);
        });
    });
}