【问题标题】:Promise array and scoping trouble while using exceljs使用 exceljs 时的 Promise 数组和范围问题
【发布时间】:2022-09-24 16:08:02
【问题描述】:

因此,我一直在与我的 Nodejs 应用程序进行斗争,以找出如何可靠地构建一系列 Promise。我已经阅读了多个重复的问题,但我似乎无法弄清楚为什么在我的情况下它会出错。我意识到我的变量范围存在问题。

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\");
   });
}

据我了解,这应该等待所有承诺得到解决,然后记录“完成”。 但这只是不等待承诺并立即看到undefined 并记录Done

所以任何人都可以帮我弄清楚为什么会这样?因为如果我在worksheet.eachRow 函数中记录promises,我可以看到所有pending promises。但是当我离开那个功能的那一刻,一切都消失了。

来自@hellikiam 的答案的解决方案:

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\");
}

他的回答是承诺反模式,因为我们已经在异步函数中,我们可以返回一个值,它会自动返回一个承诺。

    标签: javascript node.js promise exceljs


    【解决方案1】:

    您的问题是关于 javascript 中的回调计时问题。 Javascript 会将您的回调推送到调度队列中,并在包装​​函数完成后执行堆栈。

    这样,worksheet.eachRow(cb) 的回调将在Promise.all(promises) 之后执行。要同步这个过程,你最好使用像Array.prototype.map这样的同步函数。

    尝试这种方式,我添加了一些 async/await 和功能性方式来保持它的可靠性。

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

    【讨论】:

    • 是的,主要问题似乎是 .eachRow(cb) 函数,因为它被设计为不返回任何承诺。它仍未定义,因此我无法对其附加任何承诺并正在寻找解决方法。让我看看你的 sn-p 是否适合我。
    • 不,worksheet.row.map 不是有效函数,如果我尝试用eachRow 代替地图做同样的事情,我会收到错误undefined is not iterable
    • 嗯......这是一个伪代码来解释它是如何工作的。在使用它之前,您应该从 exceljs 获取行实例。我不知道您使用的模块,所以我代表您进行了搜索。 Worksheet 实例具有 rowCount 属性和 getRow(startIndex, retrievingCount) 接口。我认为您可以通过使用那些看起来像可迭代实例(数组)的类似 worksheet.getRow(0, worksheet.rowCount) 来获取行实例。查看官方参考资料 (github.com/exceljs/exceljs#rows)
    • 我认为这是一个伪代码,值得一试哈哈。但是,是的,这就是我现在正在做的事情。我最初不想走这条路,但看起来 eachRow 在这里没有做这项工作,所以我只需要自己映射行。完成后将再次发表评论。
    • @ark_knight 黑客兄弟快乐!
    猜你喜欢
    • 2013-02-25
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 2016-03-18
    • 2018-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多