El siguiente ciclo para llamar a una función asíncrona, aquí una interacción de contrato inteligente usando web3. Quiero obtener el saldo de una matriz de token llamando a balanceOf() y convertirlo posteriormente con el usdrate adjunto. Para el procesamiento paralelo estoy usando Promise.all. Obviamente, la función debajo de Promise.all() con acceso [I % currency.length] no funciona, ya que no se garantiza el resultado ordenado.
Mi pregunta es, ¿cómo puedo multiplicar las cantidades con los usdrates correctos adjuntos a los tokens y seguir usando 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; }las funciones async siempre devuelven una Promise , puede definir una función asíncrona que recibe una dirección y una moneda y devuelve una Promise que ya tiene el cálculo realizado, por lo que no tiene problemas de índice. Algo como
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); } Donde se supone que la última línea con la llamada de reduce suma todas las cantidades que tiene
¿Por qué no usar un Promise.all() anidado para agrupar todas las llamadas asincrónicas para una moneda en particular bajo una sola Promesa? Al hacer esto, también conserva la alineación del índice para procesar la respuesta.
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; }```Tienes otras respuestas geniales.
Otra forma podría ser que, puede adjuntar la tasa de USD junto con el resultado del balanceOf en la promesa misma, y luego, mientras resuelve las promesas, puede acceder a la tasa de USD directamente.
Tal vez algo como esto:
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; }