I have two async functions which duplicate a lot of code with each other, and I'm trying to figure out a way to break this duplicate code out into an alternate function which is called by both functions.
My first function looks like this (in reality there is a lot more code related to the message to aggregate):
const getAllMessageStats() = async (userId: string) => {
const messageIds = await getUserMessageIds(userId);
const messagesRead = 0;
const reactionsTotal = 0;
const moreStats = [];
for (const messageId of messageIds) {
const message = await getMessage(messageId);
if (message.read) messagesRead++;
reactionsTotal += message.reactions;
const otherStats = [];
for (const otherDataId of message.otherDataIds) {
otherData = await getOtherData(otherDataId)
otherStats.push(doLotsOfOtherCalcs(otherData));
}
moreStats.push(otherStats);
}
return {
messagesRead,
reactionsTotal,
moreStats
}
};
My second function looks something like this
const getMessageStats() = async (messageId: string) => {
const message = await getMessage(messageId);
const otherStats = [];
for (const otherDataId of message.otherDataIds) {
otherData = await getOtherData(otherDataId)
otherStats.push(doLotsOfOtherCalcs(otherData));
}
const miscData = await getMiscData(messageId);
return {
read: message.read,
reactions: message.reactions,
otherStats,
miscData
}
I tried the following:
const sharedFunction() = async (messageId: string) => {
const message = await getMessage(messageId);
const otherStats = [];
for (const otherDataId of message.otherDataIds) {
otherData = await getOtherData(otherDataId)
otherStats.push(doLotsOfOtherCalcs(otherData));
}
return {
read: message.read,
reactions: message.reactions,
otherStats
}
};
const getMessageStats() = async (messageId: string) => {
const { read, reactions, otherStats } = await sharedFunction(messageId);
const miscData = await getMiscData(messageId);
return {
read,
reactions,
otherStats,
miscData
}
};
const getAllMessageStats() = async (userId: string) => {
const messageIds = await getUserMessageIds(userId);
const messagesRead = 0;
const reactionsTotal = 0;
const moreStats = [];
for (const messageId of messageIds) {
const { read, reactions, otherStats } = await sharedFunction(messageId);
if (read) messagesRead++;
reactionsTotal += reactions;
moreStats.push(otherStats);
}
return {
messagesRead,
reactionsTotal,
moreStats
}
};
However, my function getAllMessageStats
now takes over 3 times as long to execute, especially when I have thousands of messages for a user. After coming across this post about async/await overhead, I now understand why. But my question is: am I now stuck with my original duplicated code? Surely there is a more elegant solution right?
Use Promise.all
to carry out the asynchronous functions in parallel, then loop over their results:
const sharedFunctionResults = await Promise.all(
messageIds.map(messageId => sharedFunction(messageId))
);
for (const { read, reactions, otherStats } of sharedFunctionResults) {
...
}