Home > front end >  Promise array and scoping trouble while using exceljs
Promise array and scoping trouble while using exceljs

Time:09-22

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')
}
  • Related