Reputation: 5987
In the following code, expiringContentsAllBU
is populated within async/await function getOnlyContentWhatsNewReport
which is inside the array.map()
, but expiringContentsAllBU
becomes empty when accessing it outside the businessUnits.map()
function.
const getExpiringContents = async () => {
let businessUnits = Object.keys(contentFulSpaces);
let expiringContentsAllBU = [];
businessUnits.map( async (bu) => {
await getOnlyContentWhatsNewReport(bu, (err, result) => {
if(result) {
let expiringContentsByBU = {};
expiringContentsByBU['businessUnit'] = bu;
expiringContentsByBU['expiringContents'] = result;
expiringContentsAllBU.push(JSON.parse(JSON.stringify(expiringContentsByBU)));
} else console.log('No expiring contents found for WhatsNewSection');
})
});
console.log('result', expiringContentsAllBU);
}
Upvotes: 0
Views: 209
Reputation: 11
Using async with some lodash function for sanity will help -
getExpiringContents = async() => {
let businessUnits = Object.keys(contentFulSpaces);
let expiringContentsAllBU = await Promise.map(businessUnits, async businessUnit => {
let expiringContents = await getOnlyContentWhatsNewReport(businessUnit);
if (_.isEmpty(expiringContents)) {
console.log('No expiring contents found for WhatsNewSection');
return;
}
// Choosing names that match the output means you can use the destructuring operator
let expiringContentsByBU = {
businessUnit,
expiringContents
};
// A more formalized "clone" function could help here.
return _.cloneDeep(expiringContentsByBU);
});
// As this may contain undefined elements, remove those
expiringContentsAllBU = _.compact(expiringContentsAllBU);
console.log('result', expiringContentsAllBU);
}
Upvotes: 0
Reputation: 4182
var getOnlyContentWhatsNewReport = Promise.resolve(123);
const getExpiringContents = async () => {
let businessUnits = [{ id: 1 }, { id: 2 }, { id: 3 }];
const expiringContentsAllBU = await Promise.all(businessUnits.map(async (bu) => {
return getOnlyContentWhatsNewReport.then(respBu => {
bu.businessUnit = respBu;
return bu;
}).catch((err) => {
console.log('No expiring contents found for WhatsNewSection');
return null;
});
}));
console.log('result', expiringContentsAllBU);
}
getExpiringContents();
You have to wait until the map completes and all callbacks are done. The console.log
and the subsequent code blocks will be executed before your map completes, so
const getExpiringContents = async () => {
let businessUnits = Object.keys(contentFulSpaces);
const expiringContentsAllBU = await Promise.all(businessUnits.map(async (bu) => {
return getOnlyContentWhatsNewReport(bu, (err, result) => {
if(result) {
let expiringContentsByBU = {};
expiringContentsByBU['businessUnit'] = bu;
expiringContentsByBU['expiringContents'] = result;
return JSON.parse(JSON.stringify(expiringContentsByBU);
} else {
console.log('No expiring contents found for WhatsNewSection');
return null;
}
})
}));
console.log('result', expiringContentsAllBU);
}
Upvotes: 2
Reputation: 211580
As map
is not aware of async functions you need to use something that is. One example is the Bluebird Promise.map
equivalent:
const getExpiringContents = async () => {
let businessUnits = Object.keys(contentFulSpaces);
// Use Promise.map here to convert each businessUnit entry into a record
let expiringContentsAllBU = await Promise.map(businessUnits, async (bu) => {
await getOnlyContentWhatsNewReport(bu, (err, result) => {
if (!result) {
console.log('No expiring contents found for WhatsNewSection');
return;
}
let expiringContentsByBU = {};
expiringContentsByBU['businessUnit'] = bu;
expiringContentsByBU['expiringContents'] = result;
return JSON.parse(JSON.stringify(expiringContentsByBU));
})
});
// As this may contain undefined elements, remove those
expiringContentsAllBU = expiringContentsAllBU.filter(e => e);
console.log('result', expiringContentsAllBU);
}
You could flatten this code a bit more if you made getOnlyContentWhatsNewReport
return a promise as it should instead of using a callback method. async
won't wait on callback methods so be sure that also returns a promise or this code won't wait properly.
A fully promisized version that's refactored a litlte more looks like this:
const getExpiringContents = async () => {
let businessUnits = Object.keys(contentFulSpaces);
let expiringContentsAllBU = await Promise.map(businessUnits, async businessUnit => {
let expiringContents = await getOnlyContentWhatsNewReport(businessUnit);
if (!expiringContents) {
console.log('No expiring contents found for WhatsNewSection');
return;
}
// Choosing names that match the output means you can use the destructuring operator
let expiringContentsByBU = {
businessUnit,
expiringContents
};
// A more formalized "clone" function could help here.
return JSON.parse(JSON.stringify(expiringContentsByBU));
});
// As this may contain undefined elements, remove those
expiringContentsAllBU = expiringContentsAllBU.filter(e => e);
console.log('result', expiringContentsAllBU);
}
Upvotes: 1
Reputation: 23171
You can either change your .map()
to a for loop
.
Or in your .map()
function, return promises. Then you can call await Promise.all(promiseArray)
Upvotes: 0