Shawn Tabrizi
Shawn Tabrizi

Reputation: 12434

Resolving Promise.all with a promise as part of array or object

I am trying to queue a bunch of asynchronous calls to fire in parallel. However, the promises I am queuing have additional data that I want to keep along with the promise value.

My question is: how can I pass an object or array, which contains a promise, and have the promises resolve to a value within the object?

For example, let’s generate a normal array of promises:

async function asyncFunction(input) {
  return input * 10;
}

async function main() {
  var promises = [];
  for (let i = 0; i < 10; i++) {
    promises.push(asyncFunction(i));
  }

  var result = await Promise.all(promises);
  
  document.getElementById('output').innerText = JSON.stringify(result);
}

main();
<div id='output'></div>

This is working just fine. But now if we try to place the promise into an object, with some metadata:

async function asyncFunction(input) {
  return input * 10;
}

async function main() {
  var promises = [];
  for (let i = 0; i < 10; i++) {
    promises.push({
      id: i,
      value: asyncFunction(i)
    });
  }

  var result = await Promise.all(promises);
  
  document.getElementById('output').innerText = JSON.stringify(result);
}

main();
<div id='output'></div>

The value in value is a promise, and not the resolved value.

My expected output is:

[{"id":0,"value":0},{"id":1,"value":10},{"id":2,"value":20},...]

Upvotes: 1

Views: 41

Answers (3)

Mulan
Mulan

Reputation: 135217

You could use Array.from with an async mapping function -

async function asyncFn(input) {
  return input * 10;
}

function main() {
  return Promise.all(Array.from(
    Array(10),
    async (_, i) => ({ id: i, value: await asyncFn(i) })
  ))
}

main().then(console.log, console.error)
.as-console-wrapper { min-height: 100%; top: 0; }

Upvotes: 0

Sam Logan
Sam Logan

Reputation: 3483

You could map over the array of promises and await the value key containing the promise to resolve

    async function asyncFunction(input) {
      return input * 10;
    }

    async function main() {
      var promises = [];
      for (let i = 0; i < 10; i++) {
        promises.push({
          id: i,
          value: asyncFunction(i)
        });
      }

      var result = await Promise.all(promises.map(async (promise) => ({
        id: promise.id,
        value: await promise.value
      })));

      document.getElementById('output').innerText = JSON.stringify(result);
    }

    main();

Upvotes: 1

Ry-
Ry-

Reputation: 224904

You can push promises that resolve to the format you want:

async function asyncFunction(input) {
  return input * 10;
}

async function main() {
  let promises = [];

  for (let i = 0; i < 10; i++) {
    promises.push(
      asyncFunction(i).then(value => ({
        id: i,
        value,
      }))
    );
  }

  let result = await Promise.all(promises);
  
  console.log(result);
}

main();

Upvotes: 1

Related Questions