skip to Main Content

I have an array with X promises and I need to return them in order of their setTimeout.

For example. if P1 has timeout set for 3000ms, and P2 resolves after 1000ms, we want to first return P2 and then P1. The code looks like this:

const P1 = new Promise((resolve) => {
  setTimeout(() => resolve('R1'), 3000);
});

const P2 = new Promise((resolve) => {
  setTimeout(() => resolve('R2'), 5000);
});

const P3 = new Promise((resolve) => {
  setTimeout(() => resolve('R3'), 1000);
});

async function fetchInitialData(arr) {
  return Promise.all(arr);
}

fetchInitialData([P1, P2, P3])
  .then((data) => {
    console.log('result', data);
  });

In this scenario we’re returning promises but they’re not sorted by resolve time, it would return R1, R2, R3.

We want to return them by their resolve time, so in this case: R3, R1, R2.

2

Answers


  1. Assuming I understand the example, it sounds like you want the fetchInitialData to indeed wait for all of the Promises to complete, but internally to append the result of each Promise to the result as it completes.

    Instead of returning Promise.all, you can await Promise.all after appending a .then() to each Promise, which appends its result to an array. For example:

    const P1 = new Promise((resolve) => {
      setTimeout(() => resolve('R1'), 3000);
    });
    
    const P2 = new Promise((resolve) => {
      setTimeout(() => resolve('R2'), 5000);
    });
    
    const P3 = new Promise((resolve) => {
      setTimeout(() => resolve('R3'), 1000);
    });
    
    async function fetchInitialData(arr) {
      // create array
      const result = [];
      // follow each Promise by pushing to the array
      arr.forEach(p => p.then(x => result.push(x)));
      // wait for all the Promises to complete
      await Promise.all(arr);
      // return the array
      return result;
    }
    
    fetchInitialData([P1, P2, P3])
      .then((data) => {
        console.log('result', data);
      });
    Login or Signup to reply.
  2. In this scenario we’re returning promises but they’re not sorted by resolve time, it would return R1, R2, R3.

    Right, that’s a guarantee Promise.all provides: The array it fulfills its promise with is the fulfillment values of the input promises, in input order.

    You could write your own function that instead builds the array in order of fulfillment, for instance:

    async function allInFulfillmentOrder(promises) {
        const result = [];
        await Promise.all(
            Array.from(promises, (p) => p.then((value) => result.push(value)))
        );
        return result;
    }
    

    There, we put the promises in the array as they’re fulfilled, returning the array when they’ve all been fulfilled (or when any of them is rejected, which will reject the promise our function returns).

    Live example:

    const P1 = new Promise((resolve) => {
        setTimeout(() => resolve("R1"), 3000);
    });
    
    const P2 = new Promise((resolve) => {
        setTimeout(() => resolve("R2"), 5000);
    });
    
    const P3 = new Promise((resolve) => {
        setTimeout(() => resolve("R3"), 1000);
    });
    
    async function fetchInitialData(arr) {
        return await allInFulfillmentOrder(arr);
    }
    
    fetchInitialData([P1, P2, P3]).then((data) => {
        console.log("result", data);
    });
    
    async function allInFulfillmentOrder(promises) {
        const result = [];
        await Promise.all(
            Array.from(promises, (p) => p.then((value) => result.push(value)))
        );
        return result;
    }

    The Array.from(promises, (p) => ___) is so the function supports any iterable of promises, rather than just arrays. I did that to make it consistent with Promise.all, Promise.allSettled, etc. work.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search