Promise.all 使用嵌套循环的参数转换结果

Promise.all convert result with parameter from nested loop

以下循环调用异步函数,这里是使用 web3 的智能合约交互。我想通过调用 balanceOf() 获得令牌数组的余额,然后使用附加的 usdrate 将其转换。对于并行处理,我使用 Promise.all。显然,下面的 Promise.all() 访问 [I % currency.length] 的函数不起作用,因为不能保证排序结果。

我的问题是,如何将金额乘以附加到代币的正确美元汇率并仍然使用 Promise.all?

currencies = [{
    contract: token1,
    usdrate: 0.5
  },
  {
    contract: token2,
    usdrate: 1.0
  },
  {
    contract: token3,
    usdrate: 1.05
  },
  {
    contract: token4,
    usdrate: 1.10
  },
  {
    contract: token5,
    usdrate: 1.40
  },
  {
    contract: token6,
    usdrate: 1.0
  },
  {
    contract: token7,
    usdrate: 1.0
  }
];
}

async function getUsdWealthAsync(addresses) {
  var totalWealth = 0;
  var amountPromises = [];
  for (var j = 0; j < currencies.length; j++) {
    for (var i = 0; i < addresses.length; i++) {
      amountPromises.push(currencies[j].contract.methods.balanceOf(addresses[i]).call());
    }
  }
  await Promise.all(amountPromises).then(function(amounts) {
    for (var i = 0; i < amounts.length; i++) {
      amounts[i] = Number.parseInt(amounts[i]);
      totalWealth += (amounts[i] / 100) * currencies[i % currencies.length].usdrate;
    }
  })
  return totalWealth;
}

async 函数总是 return a Promise,您可以定义一个异步函数来接收地址和货币,并且 returns a Promise计算已经完成,所以你没有索引问题。像


async function getAmount(currency, address) {
   const amount = await currency.contract.methods.balanceOf(address).call();
   return amount * currency.usdrate;
}


async function getUsdWealthAsync(addresses) {
  const amountPromises = [];
  for (const currency of currencies) {
    for (const address of addresses) {
      amountPromises.push(getAmount(currency,address)/*Remember, calling this funciton returns a Promise*/);
    }
  }
  const realAmounts = await Promise.all(amountPromises)
  return realAmounts.reduce((total,current) => total+current, 0);
}


reduce 调用的最后一行应该是您拥有的所有金额的总和

为什么不使用嵌套 Promise.all() 将针对特定货币的所有异步调用捆绑在一个 Promise 下?通过这样做,您还保留了用于处理响应的索引对齐方式。

async function getUsdWealthAsync(addresses) {
    let totalWealth = 0;
    let amountPromises = [];

    // For each of the currencies...
    for (var j = 0; j < currencies.length; j++) {
        // Create a set that will hold balance promises for this currency.
        const balancePromisesForCurrency = [];
        for (var i = 0; i < addresses.length; i++) {
            // Create those promises and add them to the set.
            balancePromisesForCurrency.push(
                currencies[j].contract.methods.balanceOf(addresses[i]).call()
            );
        }
        // Create a new promise that resolves to the list of balance results, ​
        // index-aligned to the addresses, for this currency. Add that Promise
        // to the set of per-currency Promises, index-aligned to the currencies
        // array.
        amountPromises.push(Promise.all(balancePromisesForCurrency));
    }

    // Create a new cumulative promise from the `amountPromises` array.
    await Promise.all(amountPromises).then(function (amountsForCurrency) {
        // For each of the balance lists received...
        amountsForCurrency.forEach((amounts, amountsIndex) => {
            // Get the corresponding currency.
            const currency = currencies[amountIndex];

            // Total up the balances scaled by the currency's USD rate.
            amounts.forEach((amount, idx) => {
                totalWealth += (+amount / 100) * currency.usdrate;
            });
        });
    })

    return totalWealth;
}```

您还有其他很好的答案。

另一种方法是,您可以在承诺本身中附加美元汇率以及 balanceOf 的结果,然后在解决承诺时,您可以直接访问美元汇率。

也许是这样的:

async function getUsdWealthAsync(addresses) {
  var totalWealth = 0;
  var amountPromises = [];
  for (var j = 0; j < currencies.length; j++) {
    for (var i = 0; i < addresses.length; i++) {
      const { usdrate, contract } = currencies[j];
      amountPromises.push(
        contract.methods.balanceOf(addresses[i]).call()
          .then((amount) => ({ amount, usdrate }))
      );
    }
  }

  const amounts = await Promise.all(amountPromises);

  for (var i = 0; i < amounts.length; i++) {
    const { amount, usdrate } = amounts[i];
    amount = Number.parseInt(amount);
    totalWealth += (amount / 100) * usdrate;
  }

  return totalWealth;
}