Using an array of promises, each with metadata and Promise.All() to resolve

64 Views Asked by At

In my application, I build an array of calls to a 3rd party API that each returns a promise and then use Promise.All to act on the results once they all resolve.

I find myself repeating a pattern where I use this approach but also need to store additional metadata for each entry. If it's an array of file loader promises for example, I might want to store the file type, intended destination etc. for each.

Currently, I build another array with this information and since I know the results from Promise.All will appear in the same order they were added, I can get the find both the result of the API call and the metadata using an appropriate index.

I wondered if was possible instead to create an array of containing both the API calls that returns a promise and the data as a single JavaScript object so


that both can easily be extracted after they resolve.

Despite lots of trying, I wasn't able to find a syntax that worked for me but it feels like it's possible.

Can anyone help?

function loadStuff(value, delay) {
  return new Promise((resolve) => setTimeout(() => resolve(value), delay));
}

async function loadStuffandEnhance(value, delay) {
  let result = await loadStuff(value, delay);

  result += '__enhanced';

  return result;
}

function test() {
  let loader_promises = [];
  for (let i = 0; i < 20; i++) {
    loader_promises.push(
      loadStuffandEnhance(`item${i}`, Math.random() * 1000 + 100),
    );
  }

  Promise.all(loader_promises).then((loaded_things) => {
    loaded_things.forEach(function (each) {
      console.log('resolving', each);
    });
  });
}

test();

I think this is my question distilled down to a trivial example. Instead of calling a loader and using the result once it resolves, I just return the filename after a short timeout.

1

There are 1 best solutions below

0
Brendan B On

Writing a custom function, that could return the Array of promises for each API call and any aggregated info.

Something similar to below could work.

async function fetchAPIsAndCompileResults() {
      // API endpoints
      const apiEndpoint1 = 'https://example.com/api/endpoint1';
      const apiEndpoint2 = 'https://example.com/api/endpoint2';
    
      // Function to fetch data from an API
      async function fetchData(apiUrl) {
          const response = await fetch(apiUrl);
          return await response.json();
      }
    
      // Execute both API calls concurrently and keep them as promises
      const apiCallPromises = [
        fetchData(apiEndpoint1),
        fetchData(apiEndpoint2),
  ];

  // Aggregate your specific information, from each API call into an array
  // Wait for all API call promises to resolve
  let aggregatedInfo = [];
  const results =  (await Promise.all(apiCallPromises)).forEach(result => {     // Grab your aggregated info
    if (result && result.items) {
      aggregatedInfo = [...aggregatedInfo, ...result.items];
    }
  });

  // Finally return an object containing both the promises and the aggregatedInfo
  return {
    apiCalls: apiCallPromises, // Array of promises for each API call
    aggregatedInfo // The aggregated information from all API calls once they resolve
  };
}

// Example usage
fetchAPIsAndCompileResults().then(({ apiCalls, aggregatedInfo }) => {
  Promise.all(apiCalls).then(() => {
    console.log('API Calls Completed');
    console.log(aggregatedInfo); // Aggregated information after API calls have resolved
  });
});