我有以下代码等待交易在以太坊区块链上被挖掘。
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
当前承诺(,但需要一些关于修复它的指示。
我建议将链接逻辑嵌入到promise constructor回调中。
还要确保在解析或拒绝时退出函数以避免执行其余代码。因此,在调用 resolve
和 reject
之前放置一个return
,并不是说返回值有任何意义,而只是为了确保函数的其余代码不会被执行:
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);
});
});
}