使用ExcelJS时Promise数组与变量作用域问题排查
构建Promise数组时的异步执行问题与解决方案
问题描述
在Node.js应用中构建可靠的Promise数组时遇到异常:使用worksheet.eachRow异步遍历Excel行,满足条件时将异步文件写入任务的Promise加入数组,但执行Promise.all时并未等待所有Promise完成就直接输出“Done”;在eachRow内部可看到pending状态的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"); }); }
改进后的解决方案(基于@hellikiam的答案优化,避免Promise反模式)
const fs = require('fs'); const util = require('util'); const rows = worksheet.getRows(<contentStart>, worksheet.rowCount); // 请根据你的Excel表格检查并验证行数 module.exports = async function (worksheet) { var promises = rows.map(async function (row, index) { try{ if( //some condition met ) { // stuff gets done ------- const doSomethingAsync = async () => { const res = await writeFile(`file.pdf`, pdfBytes, (_) => "Done"); return res; } let pro = await doSomethingAsync(); return pro; } } catch (e) { throw e; } }) await Promise.all(promises) console.log("Done"); }
改进点说明
- 改用
worksheet.getRows获取所有行后,通过map方法生成Promise数组,确保所有异步任务的Promise被正确收集 - 利用async函数自动包装返回值为Promise的特性,避免不必要的Promise嵌套
- 使用
await Promise.all替代.then,让代码逻辑更线性,符合async函数的写法习惯 - 添加try/catch块统一处理异常,提升代码健壮性
内容的提问来源于stack exchange,提问作者ark_knight
相关产品推荐
相关产品推荐

