假设我有一个api接口如下:
async updateNameById(@Query() id: number) {
let dbUsr = await this.usrService.findById(id)
//其他操作
await this.usrService.updateXXX({id, name})
await this.logService.log(xxxx)
return 'done'
}
从这个api的用时角度考虑 我们知道第一行findById一般数据库读都是很快的,真正影响这个接口速度的是updateXXX(数据库写操作) 那么:
- 这个update的方法前的await可以取消吗? (试了下,确实api的往返时间快了很多)
- 无关乎业务的log是不是可以取现await? (一般log都是写在middleware中,这里只是示意)
如果可以,取消await对整个服务有没有影响,比如说log的过程中,新的api请求到来了。
thx!
可以取消 取消的后果就是你不知道执行是否出错,因为await会往外抛异常,你可以try catch捕获,如果取消await,那么你想关注是否出错了只能用.then()的方式,否则它就会把err送到unhandledRejection 如果你即不关心执行的结果,也不关心执行是否出错,那么也就无所谓了 这就是nodejs里面所谓的并发应用了,你啥都await那跟写同步代码没有区别
如果无前后关联可以使用 Promise.all
@yviscool thx!
@zengming00 thx!
@zengming00 很赞
首先你得明白 await 是干什么的:
简单来说,加上 await 之后,程序会先执行更新(updateXXX),等待更新完成之后,再 logService.log(xxxx)
如果不加 await,程序会发出更新的命令,而不等待完成,然后立即 logService.log(xxxx)
就有可能发生:前端已经收到return 'done'
,而 updateXXX 还没完成,或已经出错了
所以,从代码的层面来讲,是可以取消的(也就是说,代码在语法方面没有问题)
但是从业务上讲,就要看具体需求了,如果不需要考虑 updateXXX 成功与否,那么 await 是可以不写的
但是对一般的需求,都需要加上 await
另外,你的最后一句,是另一个大问题,事务,很难一两句讲清
- 这个update的方法前的await可以取消吗? (试了下,确实api的往返时间快了很多)
可以, 只要是非关键性操作
- 无关乎业务的log是不是可以取现await? (一般log都是写在middleware中,这里只是示意)
同上, 可以
最后, 去看看await转换成的es5代码吧
await存在与否, 只会影响到是否多出一段 case: return(更进一步 迭代器是否有多1个步骤)
await右边的表达式仍旧会正常运行
另, 根据你的业务逻辑, 你应当让这几个操作完全并行
async updateNameById(@Query() id: number) {
let pmsDbUsr = this.usrService.findById(id)
//其他操作
let pmsUpdate = this.usrService.updateXXX({id, name}) // 此处name 如果不依赖于 pmsDbUsr 的完成, 则 pmsDbUsr 就不用await
let pmsLog = this.logService.log(xxxx)
// 此时已经完全并行执行了
let DbUsr = await pmsDbUsr // 等待主要操作响应
await Promise.race([delay(100), pmsUpdate]) // 等待次主要操作响应, 最长100ms, 没结果就忽略
await pmsLog // pmsLog 次要操作根据需要是否等待
return 'done'
}
await的最佳实践是 尽量延迟到要用 右边表达式的返回值时, 再 await
这样可以充分并行