Skip to content

持久化

Actors 可以持久化其内部状态并在以后恢复。持久化是指将 actor 的状态存储在持久存储中,例如 localStorage 或数据库。恢复是指从持久存储中恢复 actor 的状态。

在前端应用程序中,持久化对于在浏览器重新加载时保持状态非常有用。在后端应用程序中,持久化允许工作流跨多个请求,能够在服务重启时存活,具有容错能力,能够表示长时间运行的进程,并且可以进行审计和追踪。

在 XState 中,你可以通过 actor.getPersistedSnapshot() 获取要持久化的快照(状态),并通过 createActor(behavior, { snapshot: restoredState }).start() 恢复它:

const feedbackActor = createActor(feedbackMachine).start();

// 获取要持久化的状态
const persistedState = feedbackActor.getPersistedSnapshot();

// 持久化状态
localStorage.setItem('feedback', JSON.stringify(persistedState));

// 恢复状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));

const restoredFeedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
}).start();

持久化状态

你可以通过 actor.getPersistedSnapshot() 获取要持久化的状态:

const feedbackActor = createActor(feedbackMachine).start();

// 获取要持久化的状态
const persistedState = feedbackActor.getPersistedSnapshot();

内部状态可以从任何 actor 持久化,而不仅仅是状态机。请注意,持久化状态与 actor.getSnapshot() 的快照不同;持久化状态表示 actor 的内部状态,而快照表示 actor 最后发出的值:

const promiseActor = fromPromise(() => Promise.resolve(42));

// 获取最后发出的值
const snapshot = promiseActor.getSnapshot();
console.log(snapshot);
// 输出 42

// 获取持久化状态
const persistedState = promiseActor.getPersistedSnapshot();
console.log(persistedState);
// 输出 { status: 'done', data: 42 }

恢复状态

你可以通过将持久化状态传递给 createActor(logic, { snapshot: restoredState }) 的第二个参数中的 state 选项来恢复 actor 到持久化状态:

// 获取持久化状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));

// 恢复状态
const feedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
});

feedbackActor.start();

来自机器 actor 的动作将 不会 被重新执行,因为它们被假定已经执行过。然而,调用将被重新启动,并且生成的 actor 将被递归恢复。

深度持久化

从机器 actor 持久化和恢复状态是深度的;所有 调用的生成的 actor 将被递归持久化和恢复。

const feedbackMachine = createMachine({
// ...
states: {
form: {
invoke: {
id: 'form',
src: formMachine,
},
},
},
});

const feedbackActor = createActor(feedbackMachine).start();

// 持久化状态
const persistedState = feedbackActor.getPersistedSnapshot();
localStorage.setItem('feedback', JSON.stringify(persistedState));

// ...

// 恢复状态
const restoredState = JSON.parse(localStorage.getItem('feedback'));

const restoredFeedbackActor = createActor(feedbackMachine, {
snapshot: restoredState,
}).start();
// 将会在持久化状态下恢复 feedbackActor 和调用的 form actor

持久化状态机值

如果你只想持久化状态机 actor 的有限状态 value(以及可选的 context),你可以使用 machine.resolveState(...) 方法:

import { someMachine } from './someMachine';

const restoredStateValue = localStorage.getItem('someState');
// 假设这是 "pending"

const resolvedState = someMachine.resolveState({
value: restoredStateValue,
// context: { ... }
});

// 恢复 actor
const restoredActor = createActor(someMachine, {
snapshot: resolvedState
});

restoredActor.start();

事件溯源

持久化状态的另一种方法是事件溯源,这是一种通过重放导致该状态的事件来恢复 actor 状态的方法。事件溯源比持久化状态更可靠,因为它不太容易出现不兼容状态,并且还允许你重放动作。

实现事件溯源的一种方法是使用检查 API在事件发生时持久化事件,然后重放它们以恢复 actor 的状态:

const events = [];

const someActor = createActor(someMachine, {
// 检查并持久化事件
inspect: (inspectionEvent) => {
if (inspectionEvent.type === '@xstate.event') {
const event = inspectionEvent.event;

// 仅监听发送到根 actor 的事件
if (inspectionEvent.actorRef !== someActor) { return; }

events.push(event);
}
}
});

someActor.start();

// ...

// 假设事件存储在某个地方,例如 localStorage,
// 你可以重放它们来恢复 actor 的状态

const restoredActor = createActor(someMachine);
restoredActor.start();

for (const event of events) {
// 重放事件
restoredActor.send(event);
}

注意事项

在持久化和恢复状态时,你应该注意以下几点:

  • 不兼容状态:如果机器或 actor 逻辑发生变化,恢复的状态可能与新逻辑不兼容。
  • 重放动作:已经执行过的动作将不会被重新执行。对于这种情况,推荐使用事件溯源
  • 序列化:状态必须是可序列化的,这意味着它必须是 JSON 可序列化的。这意味着你不能持久化函数、类或其他不可序列化的值。

持久化速查表

速查表:持久化状态

const persistedState = actor.getPersistedSnapshot();

Cheatsheet: restoring state

const restoredState = JSON.parse(localStorage.getItem('feedback'));

const restoredActor = createActor(actorMachine, {
snapshot: restoredState,
}).start();

资源