如何仅在地图中执行所有等待后才增加变量值,以便我可以并行执行承诺?

How do I increase a variables value only after all the awaits is executed in a map so that I can execute the promises paralley?

嘿,这是一个非常基本的问题,但我遇到了问题。我有以下代码:

var nonce = await web3.eth.getTransactionCount(fromAccount);
    hashes.map(async hash => {
    console.log(nonce)
    const account = await web3.eth.accounts.privateKeyToAccount(process.env.PRIVATE_KEY_1)
    const transaction = await contract.methods.submitHash(hash);
    const options  = {
        nonce: web3.utils.toHex(nonce),
        to      : transaction._parent._address,
        data    : transaction.encodeABI(),
        gas     : await transaction.estimateGas({from: account.address}),
        gasPrice: web3.utils.toHex(web3.utils.toWei('20', 'gwei')),
    };
    const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
    console.log(receipt)
    nonce ++}

我只想在每次执行所有等待时增加随机数,即,我想获得 1,2,3,4.. 作为随机数值。但问题是由于异步性质 nonce 在每个循环中获得相同的值,即 1,1,1,1.. 如何在每个循环执行中将它增加 1?

问题是您在需要 for 循环的地方使用了 map。这有两个问题:

  1. 当你不使用数组时使用 map 是没有意义的 returns (someone,在某个地方,正在教授这种反模式并对他们的学生造成伤害);和

  2. map 对你的 async 函数 returns 的承诺没有做任何事情,所以你所有的 async 函数 运行并行

使用 for 循环,您不会遇到这些问题:

let nonce = await web3.eth.getTransactionCount(fromAccount);
for (const hash of hashes) {
    console.log(nonce);
    const account = await web3.eth.accounts.privateKeyToAccount(process.env.PRIVATE_KEY_1);
    const transaction = await contract.methods.submitHash(hash);
    const options = {
        nonce   : web3.utils.toHex(nonce),
        to      : transaction._parent._address,
        data    : transaction.encodeABI(),
        gas     : await transaction.estimateGas({from: account.address}),
        gasPrice: web3.utils.toHex(web3.utils.toWei('20', 'gwei')),
    };
    const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
    console.log(receipt);
    ++nonce;
}

由于您的 for 位于 await 工作的上下文中(一个 async 函数,或者很快,一个模块的顶层),它在 await 表达式,然后再继续其逻辑。


如果 工作可以并行完成,那么您可以在数组 returns 上使用 mapawait Promise.all。在 map 回调中,使用 nonce + index 而不是递增,因为 index 对于第一个散列将是 0,对于下一个散列将是 1,等等:

// In parallel
let nonce = await web3.eth.getTransactionCount(fromAccount);
const results = await Promise.all(hashes.map(async (hash, index) => {
    const thisNonce = nonce + index;
    console.log(thisNonce);
    const account = await web3.eth.accounts.privateKeyToAccount(process.env.PRIVATE_KEY_1);
    const transaction = await contract.methods.submitHash(hash);
    const options = {
        nonce   : web3.utils.toHex(thisNonce),
        to      : transaction._parent._address,
        data    : transaction.encodeABI(),
        gas     : await transaction.estimateGas({from: account.address}),
        gasPrice: web3.utils.toHex(web3.utils.toWei('20', 'gwei')),
    };
    const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
    console.log(receipt);
}));
// If you're going to keep using `nonce`, do `nonce += results.length` here.