如何在async函数中获取异步回调内的数组变量并返回至控制器
异步Excel导入错误数据无法返回Controller的问题
在Service类的async importExcel函数中,我声明了errorData数组存储Excel导入的错误信息:
- 在
readXlsxFile的then回调内可以正常访问该数组 - 但在回调外的函数末尾无法获取数组内容,无法返回给Controller
- 尝试用
setTimeout能打印数组,但依然无法返回给Controller
相关代码
Service类代码
// service class async importExcel(userId, file){ const business = await this.getBusinessByUserId(Types.ObjectId(userId)); let errorData = []; readXlsxFile(file, {schema}).then(async ({rows, errors}) => { if(errors.length === 0){ await this.excelUploadQueue.add({ rows, business }) } errors.forEach((error) => { const errors = { // 注意此处变量名与外层errors重复,易引发混淆 column: error.column, value: error.value, reason: error.reason, } errorData.push(errors) }); console.log(errorData); // 此处可正常访问errorData }) console.log(errorData); // 此处无法获取到正确数据 return errorData; // 无法返回正确数据给Controller }
Controller类代码
// controller @UseGuards(JwtAuthGuard) @UseInterceptors(FileInterceptor('file' , { storage: diskStorage({ destination: './csv', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9) cb(null, file.fieldname + '-' + uniqueSuffix + "-" + file.originalname) } }) } )) @Post('/import-excel/employee') @ApiOperation({summary: 'upload employee data via excel'}) async uploadExcel( @UploadedFile() file: Express.Multer.File, @Request() req ){ const { id: userId } = req.user; return await this.businessService.importExcel(userId, file.path); }
尝试的setTimeout代码
setTimeout(() => { console.log(errorData) // 能打印数组,但无法返回给Controller }, 100);
问题原因与解决方案
问题核心是异步操作时序问题:readXlsxFile是异步函数,then回调会在后续事件循环中执行,但函数末尾的return errorData会在回调执行前就执行,因此返回的是空数组。setTimeout只是延迟打印,无法改变函数返回的时机。
解决方法是用await替代then,将异步操作改为同步写法,确保在返回数据前完成错误信息的收集:
async importExcel(userId, file){ const business = await this.getBusinessByUserId(Types.ObjectId(userId)); let errorData = []; // 用await等待readXlsxFile执行完成 const {rows, errors} = await readXlsxFile(file, {schema}); if(errors.length === 0){ await this.excelUploadQueue.add({ rows, business }) } // 遍历错误信息,修改变量名避免与外层errors冲突 errors.forEach((error) => { const errorItem = { column: error.column, value: error.value, reason: error.reason, } errorData.push(errorItem); }); console.log(errorData); // 此处可正常获取数据 return errorData; // 现在能正确返回给Controller }
额外优化点
- 原代码中
forEach内部的变量errors与外层的errors重名,建议改为errorItem这类清晰的命名 - 使用
await后代码逻辑更线性,可读性更强,也避免了回调嵌套的问题
内容的提问来源于stack exchange,提问作者Abhay
相关产品推荐
相关产品推荐

