DEV Community

Yonz
Yonz

Posted on

Async Promise -> [Promises]

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;

Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (2)

Collapse
 
yonz profile image
Yonz • Edited

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:

if (args.handles?.length || args.handles?.length) {
  const tweetsByUsers = await fetchUsers({
    twitterAPI,
    ids: args.userIds,
    handles: args.handles
  }).then((users) => {
    if (!users) return [];
    return await Promise.all(
      Object.values(users).map((user) => {
        return fetchTweets(twitterAPI, user).then((tweetsByUser) => {
          tweets.push(...tweetsByUser);
          return tweetsByUser;
        });
      })
    );
  });
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
yonz profile image
Yonz

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.

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay