skip to Main Content

Let’s say I have async functions calling external APIs with variable response times defined as below:

async function promise1() { /* API Call */ }
async function promise2() { /* API Call */ }
async function promise3() { /* API Call */ }
// ... up to promiseN

If I wanted to run them all in parallel and wait for all of them to resolve, I would run them like result = Promise.all([promise1, promise2, promise3,...,promiseN]).

However, I have a slightly different requirement:

  1. I want to start all the promises in parallel.
  2. As soon as the first one resolves (whichever that is), I want to wait 500 milliseconds for the other promises to resolve.
  3. After that 500 ms window, I want to ignore any remaining unresolved promises.
  4. result should contain all the promises that resolved by the time the 500 ms window ends.

So for example, if promise2 resolves first at time T, I want to wait until T + 500 ms for the others to resolve. Any promises that haven’t resolved by then should be ignored.

How can I accomplish this in JavaScript?

2

Answers


  1. Instead of Promise.all you will need Promise.any (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any) and chain a .then(), incapsulating your 500ms wait into a second promise, which, when fulfilled, so 500ms passed after the first promise fulfilled, loop your promises and reject those which were not fulfilled yet.

    Login or Signup to reply.
  2. You could await for the first promise to settle with Promise.race. Then create a timeout promise (that rejects after 5 seconds), and let each of the promises race with that timeout promise. Await the results with Promise.allSettled.

    Here is a demo:

    // Helper functions
    const delay = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
    const timeout = (ms, err) => new Promise((_, reject) => setTimeout(() => reject(err), ms));
    
    // Create a list of asynchronous functions for the demo
    // They fulfull after 2, 4, 6, 8, or 10 seconds respectively, and provide as value that number of seconds.
    const asyncTasks = [2, 4, 6, 8, 10].map(i => () => delay(1000 * i, "value " + i));
    
    async function main() {
        // Create all the promises
        let promises = asyncTasks.map(task => task());
        console.log("Promises are created. Waiting for first one to settle...");
        // Get first settlement
        try { 
            await Promise.race(promises);
        } catch (e) {} // Silent also when rejection
        console.log("First promise settled. Start timer...");
        const timer = timeout(5000, "timeout");
        // Let each of the promises race with the timer:
        promises = promises.map(p => Promise.race([p, timer]));
        // Await all these race-promises to settle
        const results = await Promise.allSettled(promises);
        console.log("Here are the results:");
        for (const result of results) console.log(JSON.stringify(result));
    }
    
    main();
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search