在执行下一个代码块之前,等待多个RxJS调用



我有一个街道列表,并对它们进行迭代。在for循环中,我将为每条街道调用一个端点。端点会向我提供有关所请求街道的信息。我想把每个响应存储到一个对象数组中,在所有请求完成后,我想执行下一个代码块。这是我的问题:我执行所有调用,将所有数据存储到对象数组中,但如果我要在下一个代码块中使用我的预填充对象数组,则长度=0…这里是我的代码:

export class MyComponent{
addressInfoArray: AddressInfo[] = [];
// some code ...
prepareStreetInformations(): void {
// some code ....
this.fillArray(streets, url);
this.doSomethingWithArray(this.addressInfoArray); // <--- length = 0 and doesn't waits for finishing the fillArray() method
}
}
fillArray(streets: Street[], url: string): void { // streets has a length of 150
for (const street of streets) {
this.http.get<AddressInfo>(`${url}/street.name`).subscribe(response => {
this.addressInfoArray.push(response);
});
}
}

所以我的问题是:如何等待doSomethingWithArray((方法完全完成fillArray((方法,为什么doSometingWithArray(方法看不到我的Object Array已经填充好了?

使用RxJS,您不会真正试图强制函数调用;等待";对于先前的功能;相反,您可以构建一个可观测对象,该可观测对象根据其他可观测对象发出您需要的数据。

在您的情况下,看起来您需要一个发射AddressInfo数组的可观察对象。

我们可以定义返回Observable<Street[]>getStreets()方法,也可以定义接受street参数并返回Observable<AddressInfo>getAddressInfo()方法。

现在,我们可以使用switchMapforkJoin:创建一个将发射AddressInfo[]的可观察对象

1  export class MyComponent {
2  
3    getStreets(): Observable<Street[]> {
4      this.http.get<Street[]>(...);
5    }
6  
7    getAddressInfo(street: Street): Observable<AddressInfo> {
8      this.http.get<AddressInfo>(`${this.url}/${street.name}`); // don't subscribe here
9    }
10
11   addressInfos$: Observable<AddressInfo[]> = this.getStreets().pipe(
12     switchMap(streets => forkJoin(
13       streets.map(s => this.getAddressInfo(s))
14     ))
15   );
16 
17 }

我们使用forkJoin来创建一个可观测值,该可观测值发出其所有输入可观测值的结果数组。因此,我们将一组可观测值作为输入传递给它。

因为你有一排街道。在#13行,我们简单地将它映射到一个可观察的数组,该数组可以获得地址信息。现在,当订阅forkJoined observable时,它将发出一个AddressInfo数组(所有单个http调用的结果(

我们使用CCD_;分叉可观察";结果是可观察到的单个addressInfos$发射AddressInfo[]

请注意,我们尚未订阅。要做你的工作,你可以简单地订阅:

addressInfos$.subscibe(
infos => doSomethingWithArray(infos)
);

然而,从角度来看,一种典型的方法是将数据的发射进一步转换为模板所需的形状:

templateData$ = this.addressInfos$.pipe(
map(infos => {
//  do something will array :-)
})
);

然后,在您的模板中,您可以利用async管道:

<div *ngIf="templateData$ | async as data">
<ul>
<li *ngFor="item of data">{{ item }}</li>
</ul>
</div>

尝试使用forkJoin;

const streetsObservs = this.streets.map(street => this.http.get<AddressInfo>(`${url}/street.name`));
forkJoin(streetsObservs).subscribe((response: any) => {
this.addressInfoArray = response; // this is an array
this.doSomethingWithArray(this.addressInfoArray); // <--- length = 0 and doesn't waits for finishing the fillArray() method
});

我认为您对Observables的工作方式有一个错误的想法。在您的示例代码中,执行fillArray只是分派http调用,然后函数结束。代码中的下一步是调用doSomethingWithArray,当然此时addressInfoArray还没有填充。然后,一段时间后,当http调用完成时,将执行您在subscribe中提供的回调函数,调用addressInfoArray.push。当使用subscribe时,情况总是如此。当Observable完成时,它只会执行您传递给它的函数。

如果您想等待许多Observable完成,可以使用combineLatest。这创建了一个Observable,它发出一个包含原始Observable中所有值的数组。这就是它的工作原理:

prepareStreetInformations(): void {
this.fillArray(streets, url).subscribe(addressInfoArray => {
this.doSomethingWithArray(this.addressInfoArray)
});
}

fillArray(streets: Street[], url: string): Observable<AddressInfo[]> {
return combineLatest(
streets.map(street => this.http.get<AddressInfo>(`url/${street.name}`))
);
}

请注意,fillArray现在返回一个可订阅的Observable,并且不再对类属性进行任何更改。如果需要类属性,则必须在传递给subscribe的回调函数中定义它。

相关内容

  • 没有找到相关文章

最新更新