You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular14+NGXS中async/await Action未等待API响应的问题

问题描述

我有一个Angular 14应用,使用rxjs 7.5.0。尽管在this.store.dispatch(new DocumentAssignmentActions.DeleteDocumentAssignments...)前添加了await,但Observable并未等待Action完成API响应。

组件中的unassignAll方法

async unassignAll(agendaItemId: string) {
  try {
    console.log("calling deleteAssignments Action");
    await this.store.dispatch(new DocumentAssignmentActions.DeleteDocumentAssignments(packagedAssignments)).subscribe({
        next: (result: any) => {
            console.log("[DELETE ASSIGNMENTS - ACTION]", "Unassign all action completed");
            // 操作完成后执行逻辑
        },
        error: (error) => {
            // throw new Error(error);
        }
    });

    console.log("finished with delete action");
    // ...其他代码
  } 
  catch(error){
    // 处理错误信息
  }
}

Action实现

@Action(DocumentAssignmentActions.DeleteDocumentAssignment)
async deleteDocumentAssignment(
    context: StateContext<DocumentAssignmentStateModel>,
    action: DocumentAssignmentActions.DeleteDocumentAssignment
) {
    console.log("delete action start");
    context.patchState({ status: 'Running' }); // 设置状态为'Running'
    var model = action.model;

    // 调用API并在响应时更新状态
    await this.service.deleteDocumentAssignmentById(model)
        .then((result) => {
            const state = context.getState();
            // 处理状态...
            console.log("api response");
        })
        .catch(async (error) => {
            await context.dispatch(new DocumentAssignmentActions.AddError(DocumentAssignmentActions.AddDocumentAssignment.type, error.message));
            throw new Error(error);
        })
}

预期日志顺序

  1. calling deleteAssignments Action
  2. delete action start
  3. api response
  4. Unassign all action completed

实际日志顺序

  1. calling deleteAssignments Action
  2. delete action start
  3. Unassign all action completed
  4. api response

请问有什么办法能让它按预期工作吗?


解决方案

核心问题

store.dispatch()返回的Observable不会等待Action内部的异步操作完成,它仅通知Store触发Action后就立即完成,因此你加的await无法起到等待API响应的作用,这是日志顺序颠倒的根本原因。

修复步骤

1. 调整Action,返回Observable标记异步完成

在NgRx中,要让外部感知Action的异步操作完成,需在Action处理函数中返回Observable,将Promise转为Observable并串联后续逻辑:

@Action(DocumentAssignmentActions.DeleteDocumentAssignment)
deleteDocumentAssignment(
    context: StateContext<DocumentAssignmentStateModel>,
    action: DocumentAssignmentActions.DeleteDocumentAssignment
) {
    console.log("delete action start");
    context.patchState({ status: 'Running' });
    const model = action.model;

    // 将Promise转为Observable,处理完成逻辑
    return this.service.deleteDocumentAssignmentById(model).pipe(
        tap((result) => {
            const state = context.getState();
            // 处理状态更新
            console.log("api response");
            // 可选:分发操作完成的Action,比如DeleteDocumentAssignmentsSuccess
            // context.dispatch(new DocumentAssignmentActions.DeleteDocumentAssignmentsSuccess());
        }),
        catchError(async (error) => {
            await context.dispatch(new DocumentAssignmentActions.AddError(DocumentAssignmentActions.AddDocumentAssignment.type, error.message));
            throw error;
        })
    );
}

2. 组件中正确等待异步完成

不要直接await dispatch(),而是将Observable转为Promise,配合first()确保只接收一次完成信号:

async unassignAll(agendaItemId: string) {
  try {
    console.log("calling deleteAssignments Action");
    // 将Observable转为Promise,等待Action异步操作完成
    await this.store.dispatch(new DocumentAssignmentActions.DeleteDocumentAssignments(packagedAssignments))
      .pipe(first()) // 确保只接收一次完成信号
      .toPromise();

    console.log("[DELETE ASSIGNMENTS - ACTION]", "Unassign all action completed");
    console.log("finished with delete action");
    // ...后续操作
  } 
  catch(error){
    // 处理错误信息
  }
}

3. 可选:通过监听状态确认完成(NgRx最佳实践)

在Action中更新状态为Success,组件监听该状态变化来确认操作完成:

// Action处理中添加状态更新
tap((result) => {
    const state = context.getState();
    context.patchState({ ...state, status: 'Success' });
    console.log("api response");
})

// 组件中监听状态
async unassignAll(agendaItemId: string) {
  try {
    console.log("calling deleteAssignments Action");
    this.store.dispatch(new DocumentAssignmentActions.DeleteDocumentAssignments(packagedAssignments));
    
    // 等待状态变为Success
    await this.store.select(selectDocumentAssignmentStatus)
      .pipe(
        filter(status => status === 'Success'),
        first()
      )
      .toPromise();

    console.log("[DELETE ASSIGNMENTS - ACTION]", "Unassign all action completed");
    console.log("finished with delete action");
    // ...后续操作
  } 
  catch(error){
    // 处理错误信息
  }
}

内容的提问来源于stack exchange,提问作者John Scott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:22:47