The post is about spawning promises from the result of a promise. I found myself in a weird patter when trying to fetch tweets for a list of twitter handles.
Bad Code
if (args.handles?.length || args.handles?.length) {
const tweetsByUsers = await fetchUsers({
twitterAPI,
ids: args.userIds,
handles: args.handles
}).then((users) => {
if (!users) return [];
promises.push(
...Object.values(users).map((user) => {
fetchTweets(twitterAPI, user).then((tweetsByUser) => {
tweets.push(...tweetsByUser);
return tweetsByUser;
});
})
);
});
promises.push(tweetsByUsers);
}
...
await Promise.all(promises).catch((error) => {
console.warn("Error getting Tweets: ", error);
});
return tweets;
Working Code
Eventually I cleaned it up with:
const promises: any = [];
if (args.handles?.length || args.handles?.length) {
const twitterUsers = await fetchUsers({
twitterAPI,
ids: args.userIds,
handles: args.handles
});
if (twitterUsers) {
for (const user of Object.values(twitterUsers!)) {
const fetchTweetPromise = fetchTweets(twitterAPI, user).then((tweetsByUser) => {
tweets.push(...tweetsByUser);
return tweetsByUser;
});
promises.push(fetchTweetPromise);
}
}
}
...
await Promise.all(promises).catch((error) => {
console.warn("Error getting Tweets: ", error);
});
return tweets;
Takeaway 1: Pomise.all([promise1->[promise1a,promise1b]] does not wait for promise 1a and 1b.
Takeaway 1b: creatively trying to add promise1a and promise1b into top level fails. This is caused by a timing issue. Promise.all() will be waiting on promises before promise1a and promise1b are added to promises.
Takeaway 2 : .then( a => return new Promose())
creates havoc on its own but .then([users] => return users.map(user-> new Promise(user))
is a mind bender.
Top comments (2)
Asked you.com to fix the bad code and got the response.
Prompt: Fix the issue with the code:
The issue was with the promises.push() call which was pushing the promise instead of waiting for the promise to resolve. The correct syntax is to use Promise.all() to wait for all of the promises to resolve before returning the results.
To make sure that the tweetsByUsers variable is populated before returning, you need to use the await keyword before the Promise.all() call. This will cause the code to wait for all of the promises to resolve before returning the tweetsByUsers variable. For example:
I stubbornly wanted to solve the problem with
.then( users -> forEach
but alas I had to give up. Drop a line if you can solve it with that pattern.