如何用await替代then?Promise.all后异步请求返回空数组排查
问题:Promise.all后异步请求结果无法正确返回接口响应
问题描述
在Node.js项目中使用Supabase-Pg SQL执行数据库查询时,希望在Promise.all解析完一组异步请求后,遍历结果发起新请求并将结果存入数组。但该数组在控制台能正常打印,接口返回却为空。推测响应在Promise完成前已发送,但不清楚问题根源,也不知道如何用await替代then实现需求。相关代码如下:
export const getReportMonthly = async(req: Request & any, res: Response, next: NextFunction) => { try { let usersxData: UsersxModalidadxRolxJob[] = []; let data_monthly: HoursActivityWeeklySummary[] = []; let attendance_schedule: AttendanceSchedule[] = []; let time_off_request: TimeOffRequestRpc[] = []; let configs: IndicatorConfigs[] = []; const supabaseService = new SupabaseService(); const promises = [ supabaseService.getSummaryWeekRpcWihoutFreelancers(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => { data_monthly = dataFromDB as any; }), supabaseService.getUsersEntity(res).then(dataFromDB => { usersxData = dataFromDB as any; }), supabaseService.getAttendaceScheduleRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => { attendance_schedule = dataFromDB as any; }), supabaseService.getTimeOffRequestRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => { time_off_request = dataFromDB as any; }), supabaseService.getConfigs(res).then(dataFromDB => { configs = dataFromDB; }), ]; let attendanceInMonthly = new Array(); await Promise.all(promises).then(() => { attendance_schedule.forEach(element => { let start_date = element.date_start.toString(); let end_date = element.date_end.toString(); supabaseService.getTrackedByDateAndIDArray(start_date, end_date).then(item => { console.log(item); attendanceInMonthly.push(item); }); }); }) res.json(attendanceInMonthly) } catch (error) { console.log(error); res.status(500).json({ title: 'API-CIT Error', message: 'Internal server error' }); } }
问题根源
- 未等待后续异步请求完成:
await Promise.all(promises)只等待了初始的5个请求完成,但在then回调里的forEach中发起的getTrackedByDateAndIDArray请求都是异步的,代码没有等待这些请求完成就直接执行了res.json(attendanceInMonthly),此时数组还没被填充,所以返回空。 - 混用
await和then导致逻辑混乱:已经使用了async/await语法,却仍用then处理Promise,不仅增加代码复杂度,还容易忽略异步流程的等待逻辑。
解决方法
步骤1:用await替代初始then,简化代码
把初始promises数组里的then替换为直接返回Promise,然后用解构赋值接收结果,避免额外的变量赋值操作。
步骤2:等待forEach中的所有异步请求
将forEach改为map,把每个异步请求转为Promise并收集到新数组中,再用await Promise.all等待所有请求完成,结果会直接填充到attendanceInMonthly数组。
修改后的完整代码
export const getReportMonthly = async(req: Request & any, res: Response, next: NextFunction) => { try { const supabaseService = new SupabaseService(); // 用await直接接收所有初始请求的结果,替代then赋值 const [ data_monthly, usersxData, attendance_schedule, time_off_request, configs ] = await Promise.all([ supabaseService.getSummaryWeekRpcWihoutFreelancers(req.query.fecha_inicio, req.query.fecha_final), supabaseService.getUsersEntity(res), supabaseService.getAttendaceScheduleRpc(req.query.fecha_inicio, req.query.fecha_final), supabaseService.getTimeOffRequestRpc(req.query.fecha_inicio, req.query.fecha_final), supabaseService.getConfigs(res) ]); // 用map生成Promise数组,再await Promise.all等待所有请求完成 const attendanceInMonthly = await Promise.all( attendance_schedule.map(element => { const start_date = element.date_start.toString(); const end_date = element.date_end.toString(); // 直接返回每个异步请求的Promise return supabaseService.getTrackedByDateAndIDArray(start_date, end_date); }) ); // 所有请求完成后再返回响应 res.json(attendanceInMonthly) } catch (error) { console.log(error); res.status(500).json({ title: 'API-CIT Error', message: 'Internal server error' }); } }
关键说明
- 避免混用
await和then:async/await是更直观的异步处理方式,能让代码逻辑更线性,减少嵌套和异步流程遗漏。 forEach不适合处理异步操作:forEach不会等待内部的异步任务完成,改用map生成Promise数组后用Promise.all等待,是处理批量异步请求的标准方式。- 确保所有异步操作完成后再发送响应:只有当所有数据库请求都完成并拿到结果后,再调用
res.json,才能保证返回的数据是完整的。
内容的提问来源于stack exchange,提问作者Izlia
相关产品推荐
相关产品推荐

