I am looping through a list of objects that each have a single key-value pair, address which is type string
I want to built an object with the results of API requests for each address that tell me how often a token symbol appears. However, I think that because I'm running all of these requests in parallel, I may be over-writing the tokenKeyValue count. Is there a smarter way of doing this, that preserves the parallelization to keep things fast?
const tokenKeyValue: any = {};
let addressesCompleted = 0;
await Promise.all(segmentData.users.map(async (user: {address: string}, i) => {
try {
const tokenBalances = await getBalancesForUser(
user.address,
);
if (tokenBalances && tokenBalances.length > 0) {
for (const token of tokenBalances) {
if (tokenKeyValue[token.symbol]) {
tokenKeyValue[token.symbol]++;
} else {
tokenKeyValue[token.symbol] = 1;
}
}
}
}
catch(e) {
console.error(e);
}
finally {
addressesCompleted++;
// Check we are done looping
if (addressesCompleted === segment.users.length) {
// Calculate final tokenCount
const tokenCount = [];
for (const token in tokenKeyValue) {
tokenCount.push({
symbol: token,
value: tokenKeyValue[token],
});
}
}
}
}));
Instead of using
addressesCompleted++; // Check we are done looping if (addressesCompleted === segment.users.length)
just move that code after the await Promise.all(…):
const tokenKeyValue: Record<string, number> = {};
await Promise.all(segmentData.users.map(async (user: {address: string}) => {
try {
const tokenBalances = await getBalancesForUser(user.address);
for (const token of tokenBalances || []) {
tokenKeyValue[token.symbol] ??= 0
tokenKeyValue[token.symbol] += 1;
}
} catch(e) {
console.error(e);
}
}));
// Calculate final tokenCount
const tokenCount = Object.entries(tokenKeyValue).map(([symbol, value]) => ({symbol, value}));
You could make all the requests in parallel and then use Promise.all() to wait until all the requests resolve and then count the symbols.
const users = [{
address: '12 main st'
}, {
address: '32 main st'
}];
const promises = users.map(user => {
return getBalancesForUser(user);
});
Promise.all(promises).then((tokenBalancesList) => {
const countByTokenSymbol: any = {};
for (let tokenBalances of tokenBalancesList) {
for (let key in tokenBalances) {
const tokenBalance = tokenBalances[key];
countByTokenSymbol[tokenBalance.symbol] = countByTokenSymbol[tokenBalance.symbol] || 0;
countByTokenSymbol[tokenBalance.symbol]++;
}
}
const tokenCount = [];
for (let tokenSymbol in countByTokenSymbol) {
tokenCount.push({
symbol: tokenSymbol,
value: countByTokenSymbol[tokenSymbol]
});
}
console.log(tokenCount);
});
//placeholder getBalancesForUser function
async function getBalancesForUser(user: {address: string}) {
return [{
symbol: user.address[0]
}, {
symbol: user.address[1]
}];
}