关键点
大约 3 分钟
- 异步/等待模式 基于 future 和 promise 的思想,只是在模式的执行上略有不同。
- Promises 依赖回调并且在链式语法中以函数调用链来消费数据,但是当有大量的业务逻辑时,代码会显得臃肿且可读性较低。
- Futures 基于 tasks 构建的,通常任务包装在容器类中为用户提供数据。 一旦你想要接收该数据,你必须阻塞线程并等待它返回数据,或者干脆延迟获取该数据,直到它准备好数据。
- 使用基于 挂起函数 的 异步/等待模式,而不是阻塞线程,相对而言,他不仅代码简洁而且也没有阻塞 UI 的风险。
- 异步/等待模式 由两个函数构建:
async
包装函数调用并在协程中计算结果,然后调用await
的 挂起代码 直到准备好数据。 - 要迁移到 异步/等待模式,你必须在
async
中返回结果,并在另一个协程调用Deferred
的await
函数。通过以上方式,你就可以删除你之前使用回调来消费异步提供数据的方式。 - 延迟对象由
DeferredCoroutine
修饰。该协程还实现了Continuation
接口,允许它拦截执行流程并将 值传递 给调用者。 - 一旦延迟协程启动,它将尝试运行你传入的代码块并 将结果存储在其内部。
Deferred
接口同时继承自Job
接口,所以你可以取消它或者通过isActive
和isCompleted
来检查它的状态。- 你还可以通过调用
get CompletionExceptionOrNull
来处理延迟值可能产生的错误,并检查协程是否以异常结束。 - 通过函数调用返回
Deferreds
,你可以准备多个延迟值,并在 一个函数调用 中等待它们,从而有效地组合多个请求。 - 应该总是尽可能少的在代码中创建挂起点,使代码更易于理解。
- 使用 异步/等待模式 可以轻易的写出顺序的且看似同步的代码。这可以让你的代码变得简洁且业务逻辑也易于理解。
- 你可能会编写糟糕的协程代码。这样做可能会浪费资源或阻塞整个程序运行。这就是你的代码应该遵循结构化并发思想的原因。
- 结构化意味着你的代码要连接到其他的
CoroutineContexts
和CoroutineScopes
并且要小心的处理线程和资源管理。 - 应该总是依赖安全的
CoroutineContexts
,最好的方式是实现自己的CoroutineContexts
。 - 当实现
CoroutineScope
时,你必须要提供一个CoroutineContext
,它将用于启动每个协程。 - 将自定义的
CoroutineScope
与 完整的生命周期(例如 Android Activity)绑定起来非常有用。 - 编写 协作式 的代码非常重要,它会检查父
job
或scope
的isActive
状态以提前完成、释放资源并避免潜在的阻塞线程风险。