2

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 3

1

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()

Sign up to request clarification or add additional context in comments.

Comments

1

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)
})();

Comments

0

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

3 Comments

It's 2021, we no longer need babel to use async/await :-)
Tell me that when your client opens your site on edge or IE
IE is a hopeless case, but Edge does support async await since a few years now (caniuse.com/async-functions)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.