Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async/Await not working as expected with Promise.all and a .map function

I have a slew of async functions I'm using and I'm having a weird issue.

My code, working, looks like:

async mainAsyncFunc (metadata) {
  let files = metadata.map(data => this.anotherAsyncFunc(data.url));
  return Promise.all(files);
}

anotherAsyncFunc function looks like:

  async anotherAsyncFunc (url) {
    return await axios({
      url,
    }).then(res => res.data)
      .catch(err => {
      throw err;
    });
  }

My issue comes when I try to append more data to what the first function (mainAsyncFunc) returns. My thoughts are to do that in the map, naturally, and when all is said and done, modified it looks like:

async mainAsyncFunc (metadata) {
    files = metadata.map(data => {
        return new Promise((resolve) => {
          let file = this.anotherAsyncFunc(data.download_url);
          let fileName = data.name;
          resolve({
            file,
            fileName
          });
        });
      });
    return Promise.all(files);
}

If it's not clear, I'm getting the file itself like normal, and appending a fileName to it, then resolving that object back.

For some reason, this is returning a pending Promise, whereas I would expect it to wait for them to be fulfilled and then returned as a complete file and name in an object. Any help understanding what I'm doing wrong would be greatly appreciated.

like image 746
Zach Avatar asked Apr 03 '17 20:04

Zach


People also ask

Does Promise all work with async await?

all() along with making that function as async and promise resulting fetching will be done along with the await keyword.

Can we use async await in map function?

If you use the async await function and console out the output, then you will find the arrays of promises that are still needed to be resolved. The map doesn't resolve the promises on its own but left the stuff for the developer to resolve. So, that means you can't use async-await in the map.

Does await wait for all promises?

The keyword await is used to wait for a Promise. It can only be used inside an async function. This keyword makes JavaScript wait until that promise settles and returns its result.

Does await wait for Promise to resolve?

The async keyword before a function declaration marks it as asynchronous, and within it we can use the await keyword to wait for a promise to resolve. To wait for our promise to resolve and get the resolution as a return value from it, we just use the await keyword in-front of the promise.


2 Answers

It looks like you've solved your issue, just as a bit of a pointer, you can further simplify your code as follows:

async anotherAsyncFunc (url) {
    return (await axios({ url })).data;
}

async mainAsyncFunc (metadata) {
    let files = metadata.map(async data => ({
        file: await this.anotherAsyncFunc(data.download_url),
        fileName: data.name
    }));

    return Promise.all(files);
}
like image 178
JLRishe Avatar answered Nov 15 '22 00:11

JLRishe


Just solved the issue:

  files = metadata.map(async (data) => {
    let file = await this.anotherAsyncFunction(data.download_url);
    let fileName = data.name;
    return {
      file,
      fileName
    };
  });

I needed to wrap the anonymous function in async so I could use await inside of it. Hopefully this helps anyone else with a similar problem!

like image 28
Zach Avatar answered Nov 14 '22 23:11

Zach