【问题标题】:Using the data persistence module in Nx from Nrwl, how does the implementation of a pessimistic update differ from an optimistic update使用 Nrwl 的 Nx 中的数据持久性模块,悲观更新的实现与乐观更新有何不同
【发布时间】:2025-11-23 16:55:02
【问题描述】:

我们正在为我们的 Angular 应用程序采用 Nrwl.io 的 Nx 框架。

作为其中的一部分,我们试图了解数据持久性模块中的optimisticUpdate 和pessimisticUpdate 方法之间的底层实现差异。

根据文档,pessimisticUpdate 会先于客户端更新服务器,而使用optimisticUpdate 时,会先更新客户端。

不过这两种方法在github上的源码如下

export function pessimisticUpdate<T, A extends Action>(
  opts: PessimisticUpdateOpts<T, A>
) {
  return (source: ActionStateStream<T, A>): Observable<Action> => {
    return source.pipe(
      mapActionAndState(),
      concatMap(runWithErrorHandling(opts.run, opts.onError))
    );
  };
}

export function optimisticUpdate<T, A extends Action>(
  opts: OptimisticUpdateOpts<T, A>
) {
  return (source: ActionStateStream<T, A>): Observable<Action> => {
    return source.pipe(
      mapActionAndState(),
      concatMap(runWithErrorHandling(opts.run, opts.undoAction))
    );
  };
}

从表面上看,将更新分为乐观和悲观似乎非常有用,但从本质上讲,这两种方法的实现似乎是相同的,我们正在努力理解这两种方法的含义。

此外,当 run 方法成功完成时,调用optimisticUpdate 方法的示例代码不会调度操作。我的理解是,这将结束流 - 没有迹象表明后端调用应该返回什么。

  class TodoEffects {
  @Effect() updateTodo = this.s.optimisticUpdate('UPDATE_TODO', {
    // provides an action and the current state of the store
    run: (a: UpdateTodo, state: TodosState) => {
      return this.backend(state.user, a.payload);
    },

    undoAction: (a: UpdateTodo, e: any) => {
      // dispatch an undo action to undo the changes in the client state
      return ({
        type: 'UNDO_UPDATE_TODO',
        payload: a
      });
    }


  });

任何一直在使用 Nx 的人都可以阐明其中的区别以及我们需要在我们的服务中实施哪些操作以实现乐观更新。

【问题讨论】:

    标签: angular ngrx ngrx-effects nrwl nrwl-nx


    【解决方案1】:

    Nx 有两个版本:RxJs pipeable operator 版本和 DataPersistence 类的成员。

    前者需要一个 Observable 来管道,您需要提供它(这些是您在第一个代码块中找到的函数)。后者看起来像你的第二个代码块。

    实现的乐观和悲观之间的区别仅在于可以回滚乐观更新(由undoAction 提供)。这是因为在乐观调用中,我们立即更新 UI 并发送网络调用来更新服务器。如果服务器调用不成功,我们需要回滚我们所做的 UI 更改。这不适用于悲观调用,因为我们有一个加载微调器或其他机制来避免在调用进行时更新 UI。

    对于您的第二个代码块,run 函数没有返回操作。这应该在 Nx 文档中更新。

    class TodoEffects {
      @Effect() updateTodo = this.s.optimisticUpdate('UPDATE_TODO', {
        run: (a: UpdateTodo, state: TodosState) => {
          return this.backend(state.user, a.payload)
          .pipe(
            map(resp => ({
              type: 'UPDATE_TODO_SUCCESS',
              payload: resp
            }))
          );
        }
    

    【讨论】: