Angular 14:如何检测多组件的Observable全部完成?
解决方案
要实现“两个组件的保存操作都完成后触发服务的_actionAfterSaveSubject.next()”,核心是让服务能感知每个组件保存操作的完成状态,具体分两种场景处理:
场景1:保存操作是异步的(如HTTP请求)
这种情况需要组件将保存的异步Observable上报给服务,服务通过forkJoin等待所有异步操作完成后触发后续逻辑。
服务端修改:
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable, forkJoin, Subject } from 'rxjs'; import { take } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class ActionService { private _actionSaveSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null); actionSave$: Observable<string> = this._actionSaveSubject.asObservable(); private _actionAfterSaveSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null); actionAfterSave$ = this._actionAfterSaveSubject.asObservable(); // 存储各组件的保存完成Observable private componentSaveTasks = new Map<string, Observable<unknown>>(); // 组件调用此方法注册自己的保存完成信号 registerSaveTask(componentId: string, task$: Observable<unknown>) { this.componentSaveTasks.set(componentId, task$); } // 触发保存操作的入口(替代直接调用_actionSaveSubject.next) triggerSave(data: string) { this._actionSaveSubject.next(data); // 等待所有注册的保存任务完成 if (this.componentSaveTasks.size > 0) { forkJoin(Array.from(this.componentSaveTasks.values())) .pipe(take(1)) .subscribe(() => { this._actionAfterSaveSubject.next(data); // 清空任务列表,准备下一次保存 this.componentSaveTasks.clear(); }); } } }
组件端修改(Component1/Component2通用):
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActionService } from './action.service'; import { Subject, Observable } from 'rxjs'; import { takeUntil, switchMap, tap, finalize } from 'rxjs/operators'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-component1', template: '' }) export class Component1 implements OnInit, OnDestroy { private _unsubscribeAll = new Subject<void>(); constructor( private actionService: ActionService, private http: HttpClient ) {} ngOnInit(): void { // 创建当前组件的保存完成信号 const saveDone$ = new Subject<void>(); // 注册到服务 this.actionService.registerSaveTask('component1', saveDone$); this.actionService.actionSave$ .pipe( takeUntil(this._unsubscribeAll), skip(1), // 用switchMap包裹异步保存操作 switchMap(data => this.performSave(data).pipe( tap(() => saveDone$.next()), finalize(() => saveDone$.complete()) )) ) .subscribe(); } // 实际异步保存逻辑(示例为HTTP请求) private performSave(data: string): Observable<any> { return this.http.post('/api/save', { data }); } ngOnDestroy(): void { this._unsubscribeAll.next(); this._unsubscribeAll.complete(); } }
场景2:保存操作是同步的
如果保存是同步逻辑,只需让组件在完成保存后通知服务,服务计数达标后触发_afterSave:
服务端修改:
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ActionService { private _actionSaveSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null); actionSave$: Observable<string> = this._actionSaveSubject.asObservable(); private _actionAfterSaveSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null); actionAfterSave$ = this._actionAfterSaveSubject.asObservable(); // 预期完成保存的组件数量 private readonly expectedComponentCount = 2; private completedCount = 0; // 组件保存完成后调用此方法 reportSaveComplete() { this.completedCount++; if (this.completedCount === this.expectedComponentCount) { this._actionAfterSaveSubject.next(this._actionSaveSubject.value); this.completedCount = 0; // 重置计数 } } triggerSave(data: string) { this._actionSaveSubject.next(data); this.completedCount = 0; // 每次触发保存前重置计数 } }
组件端修改:
this.actionService.actionSave$ .pipe( takeUntil(this._unsubscribeAll), skip(1), tap(data => { // 同步保存逻辑 this.saveSyncData(data); // 通知服务保存完成 this.actionService.reportSaveComplete(); }) ) .subscribe();
注意事项
- 如果组件是动态创建/销毁的,建议用唯一ID跟踪每个组件的任务,避免计数错误;
- 触发保存时建议通过服务的
triggerSave方法统一处理,不要直接调用_actionSaveSubject.next,确保计数或任务列表能正确重置。
内容的提问来源于stack exchange,提问作者user2837961
相关产品推荐
相关产品推荐

