Building a Consistent Promise Array

Building a Consistent Promise Array

We often need to do a Promise.all(promises) where promises represent the promise array containing multiple promises. The promises will either get resolved or rejected. The way Promise.all works is that whenever, one promise from all of the promises in the promise array gets rejected, immediately the Promise.all gets rejected. This is a fail-first behavior.

Let's try to build a social hub API, where our users will have multiple social domain accounts, like Facebook, Twitter, Reddit, youtube, Instagram, etc. Our goal is to get all posts by a certain user from all these domains. Let's assume we have all our APIs ready to be utilized. And we have users who added their social domains by auth so, we know their social platform's user id too. So, let's try to fetch all the resources, shall we?

const promises = [
    TwitterApi.getTweets(userId), 
    FacebookApi.getPosts(userId), 
    RedditApi.getPosts(userId),
    YoutubeApi.getVideos(userId),
    InstagramApi.getImages(userId),
];

Promise.all(promises)
  .then(([
    tweets, 
    facebookPosts, 
    redditPosts, 
    youtubeVideos, 
    igImages
  ]) => {
    // do your thing here
  }).catch(console.log)

All good, right!

Well, not quite! You see, some users might not have a Reddit account, and maybe we don't want to bust our API's limit for these users? So, we should really include those API calls only if the user has a user id on that social platform.

const promises = [];
if (isValidUserOn(twitter)) { // we have a twitter id of that user
  promises.push(TwitterApi.getTweets(userId);
}
...
...

See, the problem? Now, or promise array is not consistent, so, if the user does not authenticate with Twitter with us, the promise array will not hold that API call, meaning our first response from Promise.all for that user will not be a Twitter response. It might be a Facebook response. i.e. we can't destructure API results like before.

.then(([
    tweets, 
    facebookPosts, 
    redditPosts, 
    youtubeVideos, 
    igImages
  ])

Now, how can we make sure, even if we don't have the API call in the promise array, the result will be consistent? The idea is to pass a falsy value for a particular promise in the promise array. In our example the user does not have a Twitter handle, so in our case, we will pass a null in the promise array.

const promises = [
    isValidUserOn(twitter) ? TwitterApi.getTweets(userId) : null, 
    ...
    ...
];

This way, the response will be consistent, i.e. we can safely destructure the promise results in the then block of the promise chain. In our case the tweets will be a falsy value.

Thats for today. Adios!