跳到内容

编写 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 的 ObservableFlowableSingle 实例。

Worker 订阅是自动管理的

虽然 Worker 带有特定于库的订阅 API 的响应式流提供支持,但您自己永远不会直接订阅 Worker。相反,Workflow 会要求基础设施运行 Worker,而基础设施将负责适当地初始化和拆除订阅,这就像子 Workflow 的生命周期由运行时自动管理一样。这使得意外泄露 Worker 的订阅成为不可能。

Workers 管理自己的内部状态

与 Workflow 不同,Workflow 实际上是定义状态转换的函数集合,而 Worker 代表长时间运行的任务。例如,Worker 通常执行网络请求。Worker 的流将打开一个套接字,然后,无论是阻塞在后台线程上还是异步执行,都会从该套接字读取数据并最终向运行它的 Workflow 发出数据。

Workers 定义自己的等价性

由于 Worker 代表正在进行中的任务,基础设施需要能够判断两个 Worker 何时代表相同的任务(以免重复执行),或者 Worker 在渲染通道之间何时发生了变化,以至于需要被拆除并为新工作重新启动。

出于这些原因,每当 Workflow 在连续的渲染通道中请求运行某个 Worker 时,都会要求它与上一个实例进行比较,并确定它们是否等价。在 Swift 中,这由 WorkerisEquivalent:to: 方法决定。符合 EquatableWorker 将自动获得基于 Equatable 实现的 isEquivalent:to: 方法。在 Kotlin 中,Worker 接口定义了 doesSameWorkAs 方法,该方法会传入上一个 Worker。

Kotlin:为什么 Worker 不使用 equals

Worker 的等价性是 Worker API 的关键部分。默认的 equals 实现只比较对象身份,这对于 Worker 来说几乎总是错误的。定义一个单独的方法强制实现者思考如何定义等价性。

Workers 是生命周期感知的

Worker 知道何时被启动(就像 Workflow 一样),但它们也知道何时被拆除。这也使它们方便用于资源管理。