Swift Concurrency 系列 02|async/await 到底解决了什么问题?
它不是单纯让代码更短,而是让异步系统重新具备被长期维护的条件
如果只看表面,async/await 好像主要解决三个问题:
- 回调太多
- 嵌套太深
- 代码太丑
但真正在项目里用一段时间后,你会发现这些都只是表象。
它真正解决的是:异步业务终于可以像正常业务一样被组织、被推理、被复用。
这不是表达上的小修小补,而是工程可维护性的变化。
一、它首先解决的是:业务流程不再被写法绑架
很多异步业务本身并不复杂,复杂的是旧写法把它写复杂了。
比如一个真实但常见的流程:
- 拉用户资料
- 检查会员状态
- 再拉首页推荐内容
- 如果其中一步失败,回退到兜底展示
- 最后更新页面状态
这本来是一个非常清楚的顺序过程。
但在 completion 时代,你经常不得不先处理这些“写法问题”:
- 成功分支写在哪
- 失败分支写在哪
- 主线程切换写在哪
- 哪一层负责提早 return
- 哪一层负责统一弹错
于是复杂度不再来自业务,而是来自表达方式本身。
async/await 最直接的收益,就是把这层额外噪音拿掉,让业务复杂度重新回到业务本身。
二、它让“依赖关系”重新变得清楚
很多异步流程不是并行的,而是强依赖的。
例如:
- 拿到登录态后,才能拿用户资料
- 拿到用户资料后,才能决定首页加载哪些模块
- 拿到实验配置后,才能决定页面展示路径
completion 当然也能表达这些关系,但问题在于:它经常把依赖关系藏在层层嵌套里。
代码能跑,但依赖链条不再清晰。
async/await 的一个核心价值,就是把这种“谁依赖谁”的关系重新拉回线性控制流:
let session = try await authService.loadSession()
let user = try await userService.loadUser(session: session)
let modules = try await homeService.loadModules(for: user)
这段代码的价值不只是好看,而是你能立刻看出:
- 顺序关系
- 中断点
- 哪一步可能抛错
这会直接影响后期修改需求时的信心,因为你终于能确定自己动的那一段在整条链路里是什么位置。
三、它显著改善了错误传播这件事
旧异步模型里,错误处理最容易碎。
因为每一层 completion 都可能失败,最后经常会形成这种局面:
- 第一层请求失败一套处理
- 第二层失败另一套处理
- 第三层失败再来一套
- 有的地方吞错
- 有的地方弹 toast
- 有的地方只打日志
你会发现,真正麻烦的不是“有错误”,而是错误路径和主流程一样被拆散了。
async/await 至少给了你统一的错误传播模型:
- 这一层处理掉
- 还是继续向上抛
- 由更高层统一兜底
也就是说,它并没有替你决定“该怎么处理错误”,但它至少让“错误怎么流动”重新变得清楚。这对业务边界尤其重要。
四、它把暂停点显式暴露出来了
很多人会忽略 await 最重要的一个意义:
它不是装饰词,而是一个提醒。
它在告诉你:
- 这里可能暂停
- 这里的上下文可能变化
- 这里之后的代码,不应该默认还处在完全相同的环境里
这对并发思维很关键。
因为异步代码真正危险的地方,往往不是调用本身,而是你在调用之后还下意识以为:
- 当前页面还在
- 当前状态还没变
- 当前对象还保持原样
而 await 至少在语法上把“这里是边界”明确标出来了。
这会迫使你开始认真思考状态有效性,而不是把异步当普通函数调用看待。
五、它让取消这件事更容易进入主设计,而不是外挂逻辑
过去很多代码也能做取消,但取消通常像是后补功能:
- 单独存一个 token
- 页面销毁时记得 cancel
- 某些场景手动把旧请求停掉
能不能做?当然能。
但问题是取消在旧模型里经常不属于主流程,而像一个外置补丁。
到了 Swift Concurrency 里,任务和取消终于更自然地被看成一组东西。
这会迫使你更早问出几个关键问题:
- 这个任务归谁拥有
- 页面离开时它该不该停
- 新任务来了,旧任务该不该失效
它没有自动帮你把取消做对,但它把“取消应该被设计进去”这件事抬到了更前面。
六、它提升的不只是个人体验,而是团队协作的一致性
这是很多人低估的一点。
一个人写代码时,completion 和 async/await 的差异可能只体现为顺不顺手。但在多人协作项目里,async/await 真正重要的地方是它让团队表达方式变得更统一。
现在你至少可以默认:
- 异步能力会出现在
async函数里 - 失败用
throw - 暂停点用
await
这种统一非常重要。
因为复杂项目里最怕的不是“技术点没学会”,而是每个人都用自己的一套异步组织方式。那样项目迟早会变成能跑,但没人能快速接手。
七、它没有解决什么
讲到这里也要反过来说清楚,async/await 没有解决这些问题:
- 它不会自动消除竞态条件
- 不会自动防止旧请求覆盖新结果
- 不会替你决定状态边界应该怎么划
- 不会自动保证 UI 更新在正确上下文里发生
所以如果一个项目原本异步设计就很乱,换成 async/await 后也可能只是“更好看地乱”。
这点一定要看清。
async/await 不是架构灵药,它只是把很多本来被写法掩盖的问题重新照亮了。
八、结论:它解决的是“异步代码还能不能被长期维护”
如果只用一句话总结,我会说:
async/await真正解决的,不是回调太丑,而是异步代码在复杂项目里越来越难被组织、被推理、被维护。
所以更准确的说法不是:
“它让代码更短。”
而是:
“它让异步代码重新具备了长期可维护的结构条件。”