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); }) }
预期日志顺序
- calling deleteAssignments Action
- delete action start
- api response
- Unassign all action completed
实际日志顺序
- calling deleteAssignments Action
- delete action start
- Unassign all action completed
- 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
相关产品推荐
相关产品推荐

