So I have been fighting with my Nodejs app to figure out how to build an array of promise reliably. I have read multiple duplicate questions but I can't seem to figure out why its going wrong in my case. Something I realize is the fact that there is something wrong with the scoping of my variables.
const fs = require('fs');
const util = require('util');
module.exports = async function (worksheet) {
var promises = [];
worksheet.eachRow(async function (row, rowNum) {
if( //some condition met ) {
// stuff gets done -------
const writeFilePromisified = util.promisify(fs.writeFile);
const doSomethingAsync = async () => {
await writeFilePromisified(`file.pdf`, pdfBytes);
console.log('file write done with promisified writeFile');
}
let pro = doSomethingAsync();
promises.push(pro);
}
}
Promise.all(promises).then(values => {
console.log("Done");
});
}
As I understood, this should have waited for all promises to be resolved and then log "Done".
But this just doesn't wait for promises and sees undefined
and logs Done
immediately.
So anyone can help me figure out why this is happening? Because if I log promises
inside the worksheet.eachRow
function, I am able to see all the pending promises
. But the moment I step out of that function, everything disappears.
Solution derived from @hellikiam's answer:
const fs = require('fs');
const util = require('util');
const rows = reportWS.getRows(contentStart, reportWS.rowCount); // check and verify row count for your excelsheet
module.exports = async function (worksheet) {
var promises = rows.map(async function (row, index) {
try{
if( //some condition met ) {
// stuff gets done -------
const writeFilePromisified = util.promisify(fs.writeFile);
const doSomethingAsync = async () => {
await writeFilePromisified(`file.pdf`, pdfBytes);
return await res;
}
let pro = doSomethingAsync();
return pro;
}
} catch (e => throw e);
}
await Promise.all(promises)
console.log("Done");
}
His answer was having promise anti-pattern because we are already in async function and we can return a value and it automatically returns a promise along with it.
CodePudding user response:
Your problem is about callback timing issue in javascript. Javascript will push your callback into schedule queue and stack will be executed after wrapper function is done.
so that, the callback of worksheet.eachRow(cb)
will be executed after Promise.all(promises)
. To synchronize this process, you'd better using synchonous function like Array.prototype.map
.
Try this way, I added some async/await and functional way to keep it reliable.
module.exports = async function (worksheet) {
var promises = worksheet.rows.map(function (row, rowNum) {
return new Promise(async (resolve, reject) =>{
try{
if( //some condition met ) {
// stuff gets done -------
const writeFilePromisified = util.promisify(fs.writeFile);
const doSomethingAsync = async () => {
await writeFilePromisified(`file.pdf`, pdfBytes);
console.log('file write done with promisified writeFile');
}
let pro = await doSomethingAsync();
return resolve(pro);
}
}
catch(e){
return reject(e)
}
})
}
const values = await Promise.all(promises)
console.log(values)
console.log('Done')
}