Pushing to an array in async function not working

20,580

Solution 1

Two problems:

  1. You shouldn't be using .map for side effects. It returns a new array so you should make use of that.

  2. .map doesn't know anything about async functions. All you are doing is creating an array of promises. When .map and your function returns, the promises are not "done" yet. You need to await all of them.

With that said:

async function getPhotoData(item, index){
    const id = item.split('#')[1];
    const response = await fetch(`http://localhost:4000/api/propertyphoto/${id}`);
    return await response.json();
}
const propertyPhotoList = await Promise.all(
    propertyData.PropertyPhotos.map(getPhotoData)
);

Solution 2

You need to use Promise.all and await:

await Promise.all(propertyData.PropertyPhotos.map(getPhotoData));

Here's the complete code with the fix:

exports.propertyById = async (req, res) => {
    try {
        const {propertyId} = _.get(req, 'params'),
        propertyData = await bService.getPropertyById(propertyId);
        console.log(propertyData);
        const propertyPhotoList = [];
        async function getPhotoData(item, index){
            const id = item.split('#')[1];
            const response = await fetch(`http://localhost:4000/api/propertyphoto/${id}`);
            const body = await response.json();
            console.log(body);
            propertyPhotoList.push(body);
        }
        await Promise.all(propertyData.PropertyPhotos.map(getPhotoData));
        console.log(propertyPhotoList);
        return res.success(res, propertyData);
    } catch (err) {
        return res.error(res, err.response.status || 500, err.response.statusText || err);
    }
}

The reason your code isn't working is because you're not waiting for all the calls to getPhotoData to finish before sending the response.

Solution 3

Because the callback is asynchronous, you need to wait for all of the mapping functions to complete before printing the new propertyPhotoList - this can be done with Promise.all. There's no need to assign to an external array, either if you just return the item you want in the new array:

const propertyPhotoList = await Promise.all(
  propertyData.PropertyPhotos.map(getPhotoData)
);

async function getPhotoData(item, index){
  const id = item.split('#')[1];
  const response = await fetch(`http://localhost:4000/api/propertyphoto/${id}`);
  const body = await response.json();
  return body;
}
Share:
20,580
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    Here is my code:

    exports.propertyById = async (req, res) => {
        try {
            const {propertyId} = _.get(req, 'params'),
            propertyData = await bService.getPropertyById(propertyId);
            console.log(propertyData);
            const propertyPhotoList = [];
            async function getPhotoData(item, index){
                const id = item.split('#')[1];
                const response = await fetch(`http://localhost:4000/api/propertyphoto/${id}`);
                const body = await response.json();
                console.log(body);
                propertyPhotoList.push(body);
            }
            propertyData.PropertyPhotos.map(getPhotoData);
            console.log(propertyPhotoList);
            return res.success(res, propertyData);
        } catch (err) {
            return res.error(res, err.response.status || 500, err.response.statusText || err);
        }
    }
    

    What's confusing me it that the 'console.log(body)' inside the asynchronous function 'getPhotoData' is returning the JSON object perfectly fine.

    But the array outside of the asynchronous function 'getPhotoData' is still returning as empty, '[]'.

    I am unsure whether the object is not being successfully being pushed, or if this is some sort of issue with async/await. I am coming from callbacks so this is still new to me.

    I am using Node.js v8.12.0 on Ubuntu 18.10.

  • Admin
    Admin over 5 years
    Yup that worked. Thanks so much!
  • Chrissy LeMaire
    Chrissy LeMaire almost 3 years
    This helped me fix my own code after about 12 hours of trying. Thank you so much!