Angular 2/4& RxJS - forEach中的订阅 - 确保流量控制不会持续到所有Observable都完成为止

时间:2017-12-09 00:53:03

标签: ajax angular rxjs observable angular-http

目标是迭代ID集合,为每个ID进行HTTP调用。对于每个ID,我使用带有返回Observable的get()方法的服务。每次调用get()方法时,我都会订阅返回的Observable并尝试将结果推送到一个数组中,最终会将其传递给另一个新操作的方法。

相关服务方式:

public get(departmentId: number): Observable<IDepartmentModel> {
    return super.get<IDepartmentModel>(departmentId);
}

注意:超类正在利用Angular Http,经过充分测试并确认其工作正常。逻辑的问题不在这里......

相关组件方法: 请注意在forEach中多次调用的departmentService.get()调用。

 setInitialDepartmentsAssignedGridData(): void {
    this.settingsForDropdownSelectedCompanyId = this.userForm.get('defaultCompany').get('defaultCompanyId').value;

    let departments: IDepartmentModel[] = [];

    this.userService.user.getValue() //confirmed: valid user is being pulled back from the userService (logic is fine here..)
        .userCompanies.find(comp => comp.companyId === this.settingsForDropdownSelectedCompanyId) // getting a valid match here (logic is fine here..)
        .departmentIds.forEach(deptId => this.departmentService.get(deptId).first().subscribe(dept => { // getting a valid department back here (logic is fine here...)
            departments.push(dept); // HERE LIES THE PROBLEM
    }));

    this.setDepartmentsAssignedRowData(departments);
}

 setDepartmentsAssignedRowData(departments: IDepartmentModel[]): void {
    console.log('setDeptAssignedRowData called'); // confirmed: method is getting called...
    console.log(departments); // confirmed: fully-composed collection of departments logged to the console...

    departments.forEach(dept => {
        console.log(dept);
    }); // Y U NO WORK!?

    departments.map((department) => {
        console.log(department); // Y U NO WORK?
        this.departmentAssignedRowData.push({
            departmentId: department.id,
            departmentName: department.name
        });
    });

    this.departmentAssignedGridOptions.api.setRowData(this.departmentAssignedRowData);
}

问题是,虽然登录到控制台的是一个完全组合的部门 - 对象数组,但它不是真的&#34;那里&#34; ;传递给setDepartmentsAssignedRowData的是一个空数组。

我确定发生的事情是,在将departments数组传递给第二个方法之前,异步操作尚未完成。我在网上看到的一些内容是使用forkJoin,但我无法看到在这种背景下的情况。我也读过concatMap可能会有效,但在这种情况下,我还不确定如何做到这一点......

在这种情况下,我如何利用RxJS确保预期的,完全合成的部门阵列真正准备好传递

感谢您提供的任何见解。非常感谢帮助!

1 个答案:

答案 0 :(得分:4)

你是对的,你需要forkJoin

let observableArray = this.userService.user.getValue()
    .userCompanies.find(comp => comp.companyId === this.settingsForDropdownSelectedCompanyId)
    .departmentIds.map(deptId => this.departmentService.get(deptId)) // map is building out an array of observables

这将是您要并行创建的http请求可观察数组。现在您可以将此数组传递给forkJoin

Observable.forkJoin(...observableArray)

forkJoin的返回将是来自observableArray的结果数组。 forkJoin中的observableArray中的所有可观察对象都已完成(因此,当所有http请求都已完成时)let observableArray = this.userService.user.getValue() .userCompanies.find(comp => comp.companyId === this.settingsForDropdownSelectedCompanyId) .departmentIds.map(deptId => this.departmentService.get(deptId)); Observable.forkJoin(...observableArray).subscribe(res => { // res = [resId0, resId1, resId2, ..., resIdX]; }); 将不会向序列中的下一个运算符发出

总而言之,代码将是

forkJoin

您提到将结果传递给另一个运算符。如果该运算符是您传递数据数组的另一个http请求(来自Observable.forkJoin(...observableArray) .flatMap(res => { return this.otherApi(res); }) .subscribe(res => { // res is the result of the otherApi call }); ),那么您可以使用flatMap运算符。

flatMap

otherApi会将您的api请求链接在一起。所以正在发生的事情是

  1. 并行运行可观察数组
  2. 完成后,运行第二个api(val one = List(50, 10, 17, 8, 16) val two = List(582, 180, 174, 159, 158) one.zip(two).map { case (a, b) => a.toDouble/b.toDouble }