5月27日 01:17
JavaScript 异步解决方案的发展历程及优缺点
JS 异步方案演进:
-
Callback(回调):异步操作完成时调用。缺点:回调地狱(嵌套超过 3 层就难读)、错误处理分散、流程控制难(并行/串行需要自己写计数器)
-
Promise(ES6):链式调用可读性提升,
.catch()统一错误处理,Promise.all/race等内置并行控制。缺点:长链仍不好读,一旦进入.then()链中间没法跳出(无法取消) -
Generator + co(ES6):
yield暂停执行,配合自动执行器实现"看起来同步"的代码。缺点:需要额外库(co),需要理解 Generator 概念,心智负担高 -
async/await(ES8):Promise + Generator 的语法精华。写法像同步,错误处理用
try-catch,分支和循环直接写。缺点:滥用串行 await 破坏并发性能(两个无关请求应放Promise.all)
追问
什么时候不推荐用 async/await?
- 简单场景(单次
.then().catch()比async包装更简洁) - 需要并发时(多个 await 写在一起是串行的)
- 顶层模块代码中(ES6 模块顶层已有 await,但 CJS 不支持)
- 数组方法中(
.map(async fn)返回 Promise 数组,需要再Promise.all)
Promise 可以取消吗?
原生 Promise 不支持取消。但有 AbortController 变通方案:fetch 传入 signal,abort 时 fetch 抛 AbortError,.then() 不会执行。真正意义的 Promise 取消需要第三方库(如 bluebird)或用 RxJS 的 Subscription。