Actor Model
当你运行一个状态机时,它就变成了一个 actor:一个可以接收事件、发送事件并根据接收到的事件改变其行为的运行进程
Actor logic
Actor logic 是 actor 的逻辑"模型"(大脑、蓝图、DNA 等)。它描述了 actor 在接收到事件时应该如何改变行为。
| 类型 | 用途 |
|---|---|
| createMachine | 最强、最完整 |
| fromPromise | 请求 / async |
在 XState 中,actor 逻辑由实现 ActorLogic 接口的对象定义,其中包含诸如 .transition(...)、.getInitialSnapshot()、.getPersistedSnapshot() 等方法。这个对象告诉解释器当接收到事件时如何更新 actor 的内部状态以及要执行哪些效果(如果有)。
| Receive events | Send events | Spawn actors | Input | Output | |
|---|---|---|---|---|---|
| State machine actors | ✅ | ✅ | ✅ | ✅ | ✅ |
| Promise actors | ❌ | ✅ | ❌ | ✅ | ✅ |
createMachine
您可以将 actor 逻辑描述为 状态机 。actor 可以做到:
- 接收事件
- 向其他 Actor 发送事件
- 调用/生成子级 Actor
- 发出其状态的快照
- 当机器到达其顶层最终状态时输出一个值
const toggleMachine = createMachine({
id: "toggle",
initial: "inactive",
states: {
inactive: {
on: {
toggle: "inactive",
},
},
active: {
on: {
toggle: "active",
},
},
},
});
const toggleActor = createActor(toggleMachine);
toggleActor.subscribe((snapshot) => {
// snapshot is the machine's state
console.log("state", snapshot.value);
console.log("context", snapshot.context);
});
toggleActor.start();
// Logs 'inactive'
toggleActor.send({ type: "toggle" });
// Logs 'active'fromPromise
Promise actor 逻辑由一个异步过程描述,该过程会在一段时间后解析(resolve)或拒绝(reject)。从 promise 逻辑创建的 actor("promise actors")可以:
- 发出 promise 的解析值
- 输出 promise 的解析值
向 promise actor 发送事件将不会产生任何效果。
const promiseLogic = fromPromise(() => {
return fetch("https://example.com/...").then((data) => data.json());
});
const promiseActor = createActor(promiseLogic);
promiseActor.subscribe((snapshot) => {
console.log(snapshot);
});
promiseActor.start();
// => {
// output: undefined,
// status: 'active'
// ...
// }
// After promise resolves
// => {
// output: { ... },
// status: 'done',
// ...
// }创建 Actor
你可以通过 createActor(actorLogic, options?) 创建一个 actor,它是某种 actor 逻辑的"活动"实例。createActor(...) 函数接受以下参数:
actorLogic: 用于创建 actor 的 actor logicoptions(可选):actor 选项
当你通过 createActor(actorLogic) 从 actor 逻辑创建一个 actor 时,你隐式地创建了一个 actor 系统 ,其中创建的 actor 是根 actor。从这个根 actor 及其后代生成的所有 actor 都是该 actor 系统的一部分。actor 必须通过调用 actor.start() 来启动,这也会启动 actor 系统:
import { createActor } from "xstate";
import { someActorLogic } from "./someActorLogic.ts";
const actor = createActor(someActorLogic);
actor.subscribe((snapshot) => {
console.log(snapshot);
});
actor.start();
// Now the actor can receive events
actor.send({ type: "someEvent" });您可以通过调用 actor.stop() 来停止根 actor,这也会停止该 actor 系统以及该系统中的所有 actor:
// Stops the root actor, actor system, and actors in the system
actor.stop();Actor 作为 Promise
您可以通过使用 toPromise(actor) 函数从任何 actor 创建一个 promise。当 actor 完成(snapshot.status === 'done')时,promise 将使用 actor 快照的 .output 解析,或者当 actor 出错(snapshot.status === 'error')时,promise 将使用 actor 快照的 .error 拒绝。
import { createMachine, createActor, toPromise } from "xstate";
const machine = createMachine({
// ...
states: {
// ...
done: { type: "final" },
},
output: {
count: 42,
},
});
const actor = createActor(machine);
actor.start();
// Creates a promise that resolves with the actor's output
// or rejects with the actor's error
const output = await toPromise(actor);
console.log(output);
// => { count: 42 }如果 actor 已经完成,promise 将立即使用 actor 的 snapshot.output 解析。如果 actor 已经出错,promise 将立即使用 actor 的 snapshot.error 拒绝。
嵌套的 Actor
在 XState 里“不是只有一个状态机”,事件必须知道“发给谁”。
Parent Actor
├── Form Actor
├── Fetch Actor
└── Timer Actor保证事件“只被一个 actor 消费”:
send({ type: "RESET" }, { to: "form" }); //明确告诉状态机,不是给我自己的,是给actor的Actor 的特点
封装:一个 Actor 拥有自己内部的、封装的状态,该状态只能由 actor 自身更新。actor 可以选择在接收到消息时更新其内部状态,但不能被任何其他实体更新。
消息异步传递:actor 间通过消息异步交互。
并发与独立性:每个 actor 独立运行,可以并发处理(逻辑上并发)。
生命周期与监督:actor 有启动、停止、失败等生命周期,常由上级管理。
内部的 actor 状态不会在 actor 之间共享。actor 共享其内部状态的任何部分的唯一方法是:
- 向其他 actor 发送事件
- 或者发出快照,这些快照可以被视为发送给订阅者的隐式事件。
Actor 可以创建(生成/调用)新的 Actor。
Actor 的生命周期
Actor 的生命周期与其被托管的状态节点绑定(invoke)或独立(spawn)。
- 创建/启动:进入某个 state,XState 创建 actor 实例并传入
input(如果有)。 - 运行中(pending):actor 执行业务逻辑,可发送事件到父机或其他 actor(若设计允许)。
- 完成 / 失败:actor 成功返回 → XState 发
done事件;失败 →error事件。 - 停止/取消:离开 state(或被 supervisor 停止)时,XState 会 stop actor(不再处理其后续结果/事件)。
Actor 的通信模式
Actor 之间只能通过 event 进行通信。
- 父 ← 子(onDone / onError / event.output):invoke 自动发送 done/error。
{
type: 'xstate.done.actor.getUser',
output: user
}父 ↔ 子(send/to):父机可用
send(..., { to: actorId })直接向某 actor 发消息。actor → 父机(sendBack):在 fromCallback 等可主动发送事件给父机。
actor ↔ actor(中介或路由):通过父机或专门的 router actor 转发消息。
Actor 的输入和输出
一个 Actor 实例的输入是可选的。
只有“会结束(complete)”的 actor,才可能产生 output,“返回值”只存在于 “完成(done)事件” 中。
