cogitoergosum
cogitoergosum

Reputation: 2471

nodejs - Returning a Promise after the end of a for loop

I need to call an async function in a for loop where every iteration 'builds' an object. At the end of the loop, this object should be resolved in a Promise so that the next function in chain can pick it up for further processing. While the iterations get the data correctly, I am not able to collect the 'built up' object and return it. I keep getting {}. Can you please help me resolve this?

async function imageDetailsCache(images) {
    var imageData = {}; // This object is built up every iteration
    var imageNo = '';
    var promises = [];
    //
    for (let i = 0; i < images.length; i++) {
        imageNo = images[i]
        promises.push(
            new Promise(function (resolve, reject) {
                imageDetails(imageNo, 'BIG').then(function (result) {
                    imageData[imageNo] = { 'BIG': result }
                    imageDetails(imageNo, 'TINY').then(function (result) {
                        imageData[imageNo] = { 'TINY': result }
                    })
                })
                resolve(imageData)
            })
        )
    }
    Promise.all(promises).then(function (result) {
        return result; // Always {}
    })
}

Upvotes: 1

Views: 381

Answers (2)

ancag
ancag

Reputation: 59

If you want to use Promises, then: I guess this will work:

async function imageDetailsCache(images) {
var imageData = {};
var promises = [];
for(let i = 0; i < images.length; i++) { // notice the let instead of var
   promises.push(
         new Promise( (resolve, reject) => {
            imageDetails(images[i], 'BIG')
                .catch(e => {reject(e)})
                .then( rBig => {
                    imageDetails(images[i], 'SMALL')
                        .catch(e => { reject(e)})
                        .then( rSmall => {
                            imageData[images[i]] = {
                                 'BIG': rBig ,
                                 'SMALL': rSmall
                            }
                            resolve ({
                                BIG: rBig,
                                SMALL: rSmall
                            });
                        });
                    });
                }
            )
        );
}
await Promise.all(promises);
return imageData;

}

imageDetailsCache(images).then((r) => {console.log(r)});

I do have to emphasize that using async & await properly (as https://stackoverflow.com/users/1048572/bergi suggested) it will make this code cleaner .

Personally I would do it like this:

async function imageDetailsCache(images) {
var imageData = {};
var promises = [];
for(let i = 0; i < images.length; i++) {
    try {
        imageData[images[i]] = {
            'BIG': await imageDetails(images[i], 'BIG') ,
            'SMALL': await imageDetails(images[i], 'SMALL')
        }
    } catch (e)  {
        console.log(e);
    }
}
return imageData;

}

imageDetailsCache(images).then((r) => {console.log(r)});

Hope it helps!

Upvotes: 0

Bergi
Bergi

Reputation: 664538

Avoid the Promise constructor antipattern! You were calling resolve before the asynchronous things in imageDetails had happened. And don't use then when working with async/await:

async function imageDetailsCache(images) {
    var imageData = {}; // This object is built up every iteration
    var promises = images.map(async (image) => {
        var result = await imageDetails(image, 'BIG');
        imageData[image] = { 'BIG': result }
        var result = await imageDetails(image, 'TINY');
        imageData[image] = { 'TINY': result };
    });
    await Promise.all(promises);
    return imageData;
}

Upvotes: 2

Related Questions