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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:36:07