Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJs - Async/Await inside async/await

I have the following code. I expect the output: START,Middle,Middle,END

but instead I get this START,Middle,END,Middle

(FYI prices array has 2 values in my example)

console.log("START");
await Promise.all(prices.map(async(price) => {
  let obj: any = {};    
  obj.normal = price.normal;

  await new Transport(obj).save(async (err: any, doc: any) => {
     console.log("Middle");
     price.transport_id = doc._id;
  });
}));

console.log("END");
console.log(prices);
like image 463
Michalis Avatar asked Dec 27 '17 20:12

Michalis


People also ask

Can we use await inside then?

The await keyword is used to get a value from a function where you would normally use . then() . Instead of calling . then() after the asynchronous function, you would simply assign a variable to the result using await .

How do I use async and await in node JS?

Async functions are available natively in Node and are denoted by the async keyword in their declaration. They always return a promise, even if you don't explicitly write them to do so. Also, the await keyword is only available inside async functions at the moment – it cannot be used in the global scope.

Does await wait for then?

The await keyword before a promise makes JavaScript wait until that promise settles, and then: If it's an error, an exception is generated — same as if throw error were called at that very place.

Can we use await inside while loop?

You need to place the loop in an async function, then you can use await and the loop stops the iteration until the promise we're awaiting resolves. You could also use while or do.. while or for loops too with this same structure. But you can't await with Array.


1 Answers

Change the inner await to a return statement, otherwise prices.map() is generating an array of entries that are undefined instead of promises.

Since Transport#save() does not return a promise, you'll need to wrap it with a Promise constructor since it is a callback-style API, or refer to the documentation which may perhaps explain how to instead return a promise.

To wrap it, you could do something like this:

// ...
obj.normal = price.normal;

return new Promise((resolve, reject) => {
  new Transport(obj).save((err: any, doc: any) => {
    console.log('Middle');

    if (err) return reject(err);

    price.transport_id = doc._id;
    resolve(price);
  });
});
like image 77
Patrick Roberts Avatar answered Oct 23 '22 05:10

Patrick Roberts