如何等待this.getStock执行完成后再发送接口响应
问题根因
返回空数组是JavaScript异步执行时序导致的:getStock是返回Promise的异步方法,for循环执行时只会触发异步任务、不会阻塞等待任务返回,循环结束后会立刻执行后续的res.send逻辑,此时所有getStock的查询回调还没执行,reply数组还没被写入数据,自然返回空。
另外原有代码res.send(reply).sendStatus(200)存在写法错误:res.send执行后已经完成响应发送,后续链式调用sendStatus会触发重复响应报错。
修复方案
核心是等待所有库存查询的异步任务全部执行完成后,再发送响应,两种常用写法可选:
async/await 写法(推荐,可读性更高)
async stock(@Req() req: Request, @Res() res: Response, next: NextFunction) { const parts = req.body.cxml.credentials[0].partslist[0] // 批量构造所有库存查询的Promise任务 const stockQueryTasks = parts.part.map(partItem => { const partNumber = JSON.stringify(partItem.partnumber[0]).replace(/['"]+/g, '') return this.getStock(partNumber) }) // 等待所有查询完成,直接拿到顺序匹配的结果数组 const reply: Stock[] = await Promise.all(stockQueryTasks) console.log(reply) // 正确设置状态码并发送响应 res.status(200).send(reply) }
Promise then 链式写法
如果不使用async/await语法,可直接收集所有Promise后统一等待回调:
stock(@Req() req: Request, @Res() res: Response, next: NextFunction) { const parts = req.body.cxml.credentials[0].partslist[0] const stockQueryTasks = parts.part.map(partItem => { const partNumber = JSON.stringify(partItem.partnumber[0]).replace(/['"]+/g, '') return this.getStock(partNumber) }) Promise.all(stockQueryTasks) .then((reply: Stock[]) => { console.log(reply) res.status(200).send(reply) }) .catch(err => { // 必须加错误兜底,避免查询失败时接口挂死无响应 next(err) }) }
注意事项
- 单个HTTP请求只能发送一次响应,需要同时设置状态码和响应内容时,使用
res.status(状态码).send(响应内容)的写法,不要链式调用多个响应方法 - 多个并行异步任务不要依赖循环内手动push结果的方式收集数据,
Promise.all除了自动等待所有任务完成,还能保证返回结果的顺序和传入任务的顺序一一对应,避免因为接口返回速度差异导致结果顺序错乱 - 所有异步逻辑必须加错误捕获,避免单个查询失败导致整个接口超时无响应
内容的提问来源于stack exchange,提问作者comsma
相关产品推荐
相关产品推荐

