MazMat
MazMat

Reputation: 2094

Synchronic code with map functions

I think I got totally lost, I thought I had at least some grasp on async stuff, but this particular case got me confused.

I perform a search on the database and expect an array of results. Then i map through the array, check for flag and push info to the array.

However, I'm doing async calls wrong, because when I console log the finalData it's always empty, therefore it resolves before it should.

Here are my attempts, tried it both ways:

let finalData = [];

let lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);

db.find({ createdAt: { "$gte": lastWeek } }).then((records, err) => {

    async function test() {
        let array = _.map(records, (record) => {
            db2.find({ 'foo': record.id }).then((bar, err) => {

                if (bar.endDate) {
                    let data = `Email: ${record.email}`;
                    finalData.push(data);
                } else {
                    let data = `Email: ${record.email}`;
                    finalData.push(data);
                }
            });
        });

        await Promise.all(array).then(() => {
            console.log(finalData);
        });

    }

    test();
});

and:

db.find({ createdAt: { "$gte": lastWeek } }).then((records, err) => {

    let promise1 = new Promise((resolve, reject) => {
        _.map(records, (record) => {
            db2.find({ 'foo': record.id }).then((bar, err) => {

                if (bar.endDate) {
                    let data = `Email: ${record.email}`;
                    finalData.push(data);
                } else {
                    let data = `Email: ${record.email}`;
                    finalData.push(data);
                }
            });
        });

        resolve();
    });

    promise1.then(() => {
        console.log(finalData);
    })
});

Results are the same, I'm doing something wrong.

Upvotes: 0

Views: 56

Answers (1)

Bergi
Bergi

Reputation: 664538

  • Your basic attempt looks fine, you just forgot to return the promises from your map callback so that array was actually an array of undefined values, not of promises
  • You don't need that finalData array to manually push to. Just resolve your promises with the respective value, and Promise.all will collect them into an array of results anyway
  • A then callback doesn't take a second err parameter - if your function returns a promise already, it either calls a fulfillment callback or a rejection callback.
  • Don't mix then and async/await style

let lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);

const records = await db.find({ createdAt: { "$gte": lastWeek } });
let promises = records.map(async (record) => {
    const bar = await db2.find({ 'foo': record.id });
    if (bar.endDate) {
        return `Email: ${record.email}`;
    } else {
        return `Email: ${record.email}`;
    }
});

const finalData = await Promise.all(promises)
console.log(finalData);

Or alternatively:

let lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);

return db.find({ createdAt: { "$gte": lastWeek } }).then(records => {
    let promises = records.map(record => {
        return db2.find({ 'foo': record.id }).then(bar => {
//      ^^^^^^
            if (bar.endDate) {
                return `Email: ${record.email}`;
//              ^^^^^^
            } else {
                return `Email: ${record.email}`;
//              ^^^^^^
            }
        });
    });
    return Promise.all(promises);
//  ^^^^^^
}).then(finalData => {
    console.log(finalData);
});

Upvotes: 1

Related Questions