Angular中如何等待Firestore数据加载完成后再执行后续函数
当前场景
我有一个从Cloud Firestore读取数据的服务,代码位于employee.service.ts:
getEmployeeList(orgID: string) { return this.firestore.collection('orgData').doc(orgID).collection('employeeList').snapshotChanges(); }
我在组件中调用该服务读取数据,组件代码位于component.ts:
export class ManageEmployeesComponent implements OnInit { newEmployee: FormGroup; Employees: Employee[]; selectedOrganization: string; @Input() set selectOrg(org: string) { this.selectedOrganization = org; this.getEmployees(); this.formsInit(); } getEmployees() { this.employeeService.getEmployeeList(this.selectedOrganization).subscribe(data => { this.Employees = data.map(e => { return { id: e.payload.doc.id, ...e.payload.doc.data() as Employee }; }) }); } formsInit() { //some reactive form stuff } }
问题描述
每次selectOrg输入属性被赋值时,会同步执行getEmployees和formsInit。但我需要等getEmployees()的所有数据加载完成后,再运行formsInit()。
问题咨询
我要如何改写代码,才能让formsInit等待getEmployees的异步操作全部执行完成后再触发?
补充说明1:
我目前想到的最优方案是修改getEmployees(),使其接受一个可选的函数参数,在数据获取完成后调用该函数,但不确定这种方案的实用性和整洁度如何。
解决方案
这里提供两种符合Angular+RxJS编码规范的实现方案,都比传入回调参数的方案更易维护:
方案1:最小改动实现
直接将formsInit的调用移到getEmployees的订阅回调末尾,数据映射完成后执行,同时删除setter里的formsInit调用:
修改后的getEmployees:
getEmployees() { this.employeeService.getEmployeeList(this.selectedOrganization).subscribe(data => { this.Employees = data.map(e => { return { id: e.payload.doc.id, ...e.payload.doc.data() as Employee }; }); // 数据加载完成后执行表单初始化 this.formsInit(); }); }
修改后的setter:
@Input() set selectOrg(org: string) { this.selectedOrganization = org; this.getEmployees(); }
方案2:生产环境推荐实现(避免内存泄漏+旧请求覆盖问题)
用响应式流处理组织切换逻辑,自动取消未完成的旧请求,同时统一管理订阅生命周期:
export class ManageEmployeesComponent implements OnInit, OnDestroy { newEmployee: FormGroup; Employees: Employee[]; selectedOrganization: string; // 组织切换流 private orgChange$ = new Subject<string>(); // 销毁流,用于自动取消所有订阅 private destroy$ = new Subject<void>(); @Input() set selectOrg(org: string) { this.orgChange$.next(org); } ngOnInit() { this.orgChange$.pipe( // 切换新请求时自动取消上一个未完成的请求 switchMap(org => this.employeeService.getEmployeeList(org)), // 数据映射逻辑 map(data => data.map(e => ({ id: e.payload.doc.id, ...e.payload.doc.data() as Employee }))), // 组件销毁时自动取消订阅 takeUntil(this.destroy$) ).subscribe(employeeList => { this.Employees = employeeList; this.formsInit(); }); } formsInit() { // 表单初始化逻辑 } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } }
关于你提到的回调参数方案
该方案虽然可实现需求,但会提升代码耦合度,不符合RxJS响应式编码习惯,后续维护成本更高,不推荐使用。
内容的提问来源于stack exchange,提问作者Kris Kamweru
相关产品推荐
相关产品推荐

