编写 Worker¶
Worker
是一个协议(在 Swift 中)或接口(在 Kotlin 中),它定义了一个可由 Workflow
执行的异步任务。Worker
只会发出输出,它们没有 Rendering
类型。它们类似于具有 Void
/Unit
渲染类型的子 Workflow。
Workflow 可以通过在调用 render
方法时将 Worker 传递给 RenderContext.runningWorker
方法,来请求基础设施等待 Worker 的结果。Workflow 可以处理来自 Worker
的输出。
Workers 提供了一个通往命令式世界的声明式窗口¶
尽管编写声明式代码很好,但真实的应用程序需要与命令式 API 交互。Workers 允许包装命令式 API,以便 Workflow 可以以声明式方式与其交互。Workflow 无需发出命令式“启动此任务、执行此操作、现在停止”的调用,而是可以声明“我声明此任务现在应该正在运行”,并让基础设施负责确保任务在必要时实际启动,如果在进行中则继续运行,并在不再需要时将其拆除。
Workers 可以执行副作用¶
与 Workflow 的 render
方法不同,后者可以多次调用且必须是幂等的,Worker 会被启动并一直运行直到完成(或取消),这与运行它们的 Workflow 实际被渲染了多少次无关。这意味着,例如,当 Workflow 进入特定状态时只需执行一次的副作用,应该放在 Workflow 在该状态下运行的 Worker
中。
Workers 是冷的响应式流¶
Workers 实际上是带有明确等价性的异步流的简单包装器。在 Swift 中,Worker 由 ReactiveSwift SignalProducer
提供支持。在 Kotlin 中,它们由 Kotlin Flow
提供支持。它们也很容易从 Reactive Streams Publishers 派生,包括 RxJava 的 Observable
、Flowable
或 Single
实例。
Worker 订阅是自动管理的¶
虽然 Worker 由带有特定于库的订阅 API 的响应式流提供支持,但您自己永远不会直接订阅 Worker。相反,Workflow 会要求基础设施运行 Worker,而基础设施将负责适当地初始化和拆除订阅,这就像子 Workflow 的生命周期由运行时自动管理一样。这使得意外泄露 Worker 的订阅成为不可能。
Workers 管理自己的内部状态¶
与 Workflow 不同,Workflow 实际上是定义状态转换的函数集合,而 Worker 代表长时间运行的任务。例如,Worker 通常执行网络请求。Worker 的流将打开一个套接字,然后,无论是阻塞在后台线程上还是异步执行,都会从该套接字读取数据并最终向运行它的 Workflow 发出数据。
Workers 定义自己的等价性¶
由于 Worker 代表正在进行中的任务,基础设施需要能够判断两个 Worker 何时代表相同的任务(以免重复执行),或者 Worker 在渲染通道之间何时发生了变化,以至于需要被拆除并为新工作重新启动。
出于这些原因,每当 Workflow 在连续的渲染通道中请求运行某个 Worker 时,都会要求它与上一个实例进行比较,并确定它们是否等价。在 Swift 中,这由 Worker
的 isEquivalent:to:
方法决定。符合 Equatable
的 Worker
将自动获得基于 Equatable
实现的 isEquivalent:to:
方法。在 Kotlin 中,Worker
接口定义了 doesSameWorkAs
方法,该方法会传入上一个 Worker。
Kotlin:为什么 Worker 不使用 equals
?
Worker 的等价性是 Worker API 的关键部分。默认的 equals
实现只比较对象身份,这对于 Worker 来说几乎总是错误的。定义一个单独的方法强制实现者思考如何定义等价性。
Workers 是生命周期感知的¶
Worker 知道何时被启动(就像 Workflow 一样),但它们也知道何时被拆除。这也使它们方便用于资源管理。