在Node.js中对同步函数使用await会对性能产生什么影响?
预先将同步函数声明为异步的代价分析
你提到的为了方便未来扩展、提前把同步函数声明为async的做法,核心目的是后续如果函数要改成异步实现,不需要修改所有调用方的await逻辑,但这种写法会带来多方面的代价:
1. 不可忽视的性能损耗
- async函数无论返回什么值,都会自动封装为
Promise实例,相比纯同步函数多了Promise对象创建、内存分配的开销 - 调用时使用
await关键字时,哪怕对应Promise已经是完成状态,JS引擎也会挂起当前执行上下文,将后续逻辑推到微任务队列,等待当前同步执行栈清空后再恢复执行。仅就你给出的加法示例来说,await sum(a,b)的执行效率比直接调用同步sum函数低几十到上百倍,如果是在高频调用、循环调用的场景下,性能差距会被进一步放大 - 哪怕你不使用await,调用async函数也会返回Promise,后续取值必须走
.then()或者await,相比同步取值多了一层逻辑开销
2. 错误处理成本升高
- 纯同步函数的错误是同步抛出的,可以直接用常规
try/catch捕获,也可以直接在上层调用栈自然冒泡 - 改为async函数后,哪怕是参数非法、类型错误这类同步阶段就能发现的问题,也会被封装为Promise的reject状态,必须使用
try/catch包裹await调用、或者追加.catch()方法才能捕获,一旦遗漏处理就会触发未捕获的Promise rejection异常,在Node.js环境会直接导致进程崩溃,前端环境也会抛出全局错误
3. 代码语义被破坏
- async函数的原生语义就是「该函数包含异步逻辑(IO、定时器、事件监听等),返回结果是异步获取的」,给纯同步逻辑的函数加上async标记,会误导后续维护者错误判断函数的实现逻辑和执行时序,额外增加理解成本,甚至可能因为误判时序写出隐性bug
- 比如开发者看到async标记会默认认为函数执行不会阻塞当前同步栈,可能会在不适合异步的场景下调用该函数
4. 适用场景受限,增加额外适配成本
- 很多原生同步API要求传入同步函数,比如数组的
map、filter、reduce等迭代方法,如果你传入async函数,得到的结果会是Promise数组,而非预期的普通数组,必须额外调用Promise.all等方法处理才能得到最终结果,反而增加了不必要的适配代码 - 同步函数可以在任何同步上下文里直接调用,改为async之后就只能在异步上下文里用await取值,使用场景被大幅收窄
内容的提问来源于stack exchange,提问作者Motty Milshtein
相关产品推荐
相关产品推荐

