Home > Software design >  Racing Javascript promises while ensuring all promises complete
Racing Javascript promises while ensuring all promises complete

Time:11-06

I need to get the result of a Javascript Promise that returns the fastest, but I want to continue invoking the logic encapsulated within the other 2 "losing" promises, irrespective of who wins. Example below.

// The 3 promises I care about
const fetchFromGoogle: Promise<T> = googlePromise()
const fetchFromAmazon: Promise<T> = amazonPromise()
const fetchFromCloudflare: Promise<T> = cloudflarePromise()

// The promise that invoked its logic the fastest
const winner: T = Promise.race([fetchFromGoogle, fetchFromAmazon, fetchFromCloudflare])

In this scenario, if fetchFromAmazon call wins in terms of speed, then I would return the result to the client, but continue running the other two promises async.

This is being executed from within a Cloudflare Worker and the ability to return the winning promise whilst continuing the evaluation of the other functions will be supported via the waitUntil API linked below.

I've evaluated two options:

  1. Some Javascript API that I'm unaware of that can do this for me
  2. Use something like this to determine which promises lost and run them using Cloudflare Workers context.waitUntil call which will ensure that the logic will continue evaluating despite having returned the result back to the client.

It's in my understanding Promise.All would not satisfy this criteria because I would never early return the winning promise as we wait for all 3 to complete.

CodePudding user response:

You can just combine a .then() handler with Promise.race(). The .then() handler lets you handle each result individually. The Promise.race() tells you when the first one is done (and optionally what its value was):

// The 3 promises I care about
const fetchFromGoogle: Promise<T> = googlePromise().then(result => { 
    /* process this one here whenever it completes */
    return someValue;
});
const fetchFromAmazon: Promise<T> = amazonPromise().then(result => { 
    /* process this one here whenever it completes */
    return someValue;
});
const fetchFromCloudflare: Promise<T> = cloudflarePromise().then(result => { 
    /* process this one here whenever it completes */
    return someValue;
});

// Tells you when the first one is done and what its value was
const winner: T = await Promise.race([fetchFromGoogle, fetchFromAmazon, fetchFromCloudflare]);

Keep in mind that Promise.race() tracks the first promise to settle (success or failure) - it does not give you the first promise to fulfill. So, if the first promise to settle rejects, then that's what Promise.race() will give you (the rejected promise).

You can use Promise.any() instead to get the first fulfilled promise.

  • Related