2

I have a problème which I can't seem to figure out. I need this await call to happen only when it finishes one by one in the loop, but it seems like its just calling it twice in the same time quickly, which is not making the api post work correctly.

I've tried to use async, await, but the await doesn't seem to like it being in two loops. Has anyone got a better solution?

async pushToCreate() {
    const toCreate = this.json.toCreate

    let counter = 0

    // toCreate Sample = { en: [{}, {}] }, { fr: [{}, {}] }

    Object.keys(toCreate).forEach((item) => {
        toCreate[item].forEach((el) => {
            const lang = item
            const dataContent = el

            await this.wp.products().param('lang', lang).create({
                title: dataContent.dgn,
                fields:  dataContent,
                status: 'publish'
            }).then(function( response ) {
                counter++
            }).catch(function(err) {
                console.log('error in create', err)
            })

            console.log('await finished')
        })
    })

    // should console log when above is finished
    console.log('END')
}
anon
  • 594
  • 6
  • 25
  • you are using lambda function inside the foreach loops, but they are synchronous, you need to make this function async – dor272 May 14 '20 at 18:55
  • 2
    You might want to read [the answers to this question](https://stackoverflow.com/q/37576685/9374673). – Mihai Chelaru May 14 '20 at 18:55

2 Answers2

1
  1. If you want to await for promises forEach will not help you. To make it work you should use:
    • for/for..in/for..of loops for the sequential processing and await for each Promise to become fulfilled on each iteration
    • map for the parallel processing which will return an array of promises and after that you can await for them to become fulfilled with Promise.all()
  2. If you use async/await it looks more clear to use try/catch instead of then/catch chaining

Try this out if you need sequential processing:

...

  let lang;
  let dataContent;

  for (const item in toCreate) {
    lang = item;

    for (let i = 0; i < toCreate[lang].length; i++) {
      dataContent = toCreate[lang][i];

      try {
        await this.wp.products().param('lang', lang).create({
          title: dataContent.dgn,
          fields: dataContent,
          status: 'publish',
        });

        counter++;
      } catch (err) {
        console.log('error in create', err);
      }

      console.log('await finished');
    }
  }

...

or this if you need parallel processing:

...

  let lang;
  let dataContent;

  await Promise.all(
    Object.keys(toCreate).map(async item => {
      lang = item;

      await Promise.all(
        toCreate[lang].map(async el => {
          dataContent = el;

          try {
            await this.wp.products().param('lang', lang).create({
              title: dataContent.dgn,
              fields: dataContent,
              status: 'publish',
            });

            counter++;
          } catch (err) {
            console.log('error in create', err);
          }

          console.log('await finished');
        }),
      );
    }),
  );

...

Here is a good explanation of the sequence and parallel asynchronous calls handling using async/await: Using async/await with a forEach loop

olsydko
  • 1,166
  • 1
  • 5
  • 5
0

I believe there are a few issues with your code.

The first is that await only works when a function returns a promise. Functions that return promises initially return a value that indicates that a promise is pending. If the function you have on the right side of await does not return a promise, it will not wait. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

The second is that you are also using the .then() method, which triggers it's callback argument when the promise is fulfilled. I do not think you can use both await and .then().https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

If you want to have a similar format as the .then() .catch() pattern, you could use a try/catch block with the async/await.

async function f() {

  try {
    let response = await fetch('/example');
    let user = await response.json();
  } catch(err) {
    // catches errors both in fetch and response.json
    alert(err);
  }
}

https://javascript.info/async-await