Run promises in an array of an array of objects

Viewed 119

I'm having trouble running Promises in an array of arrays of objects.

I have a hardcoded example of some data

const page = [
    [
      {
        id: 1,
        text: 'sentence 1'
      },
      {
        id: 2,
        text: 'sentence 2'
      }
    ],
    [
      {
        id: 3,
        text: 'sentence 3'
      }
    ]
  ]

A function called getSentiment takes a string and returns a promise

function getSentiment (sentence) {
  const rand = Math.random()
  if (rand < 0.3) { 
    return Promise.resolve(-1) 
  } else if (rand < 0.6) { 
    return Promise.resolve(0) 
  } else { 
    return Promise.resolve(1)
 }
}

Here is my code that maps this nested array that creates/adds a new key/property to the objects.

const resolvedPage = page
    .map(line => line
      .map(async sentence => {
        sentence.sentiment = await getSentiment(sentence.text)
        return sentence
      }))

getSentiment is called with async/await to get the value and assign to sentiment property and then return the object.

When I run console.log(resolvedPage) I get this

[
  [ Promise { <pending> }, Promise { <pending> } ],
  [ Promise { <pending> } ]
]

The result I expect should look like this:

[
[
  {
    id: 1,
    text: 'sentence 1',
    sentiment: 0
  },
  {
    id: 2,
    text: 'sentence 2',
    sentiment: -1
  }
],
[
  {
    id: 3,
    text: 'sentence 3',
    sentiment: 1
  }
]

]

I tried using Promise.all but I'm not sure how to do it since my data is nested in an outer array.

3 Answers

You can use Promise.all to wait for an array of promises to finish. With flatMap you can first map each line to an array of promises and then merge them together (flatten it), so it results in one big array of promises. So the updating is done inside the map. The return promises of the map calls are only used to wait for the promises to finish.

const page = [
    [{ id: 1, text: 'sentence 1' },
     { id: 2, text: 'sentence 2' }
    ],
    [{ id: 3, text: 'sentence 3' }]
  ]

function getSentiment (sentence) {
  const rand = Math.random()
  if (rand < 0.3) { 
    return Promise.resolve(-1) 
  } else if (rand < 0.6) { 
    return Promise.resolve(0) 
  } else { 
    return Promise.resolve(1)
 }
}

const main = async () => {
  const promises = page
    .flatMap(line => line.map(async sentence => {
      sentence.sentiment = await getSentiment(sentence.text)
    }))
  await Promise.all(promises)
  console.log(page)
}
main()

you can wrap the async code in a function and use Promise.all For example

(async () => {
  const resolvedPage = await Promise.all(
    page.map(
      async line => await Promise.all(
        line.map(
          async sentence => ({ ...sentence, sentiment: await getSentiment(sentence.text) })
        )
      )
    )
  );
  
  console.log(resolvedPage)
})();

There is something call for


export async function myFunc (list) {
    for (const items of list) {
        
        for (const item of items){
             const result = await (your promise);
             //// rest of code
        }

   }

}

You might need to add the proper @babel/plugins to use it

Related