[英]RxJS Observable forkJoin Not Executing in Parallel
我有以下代碼,對於我的一生,無法弄清楚為什么請求不會同時執行。 我對 RxJS 和 observables 還是陌生的,因此對於改進以下代碼的任何幫助也將不勝感激。 基本上,我在后端調用 REST API 以獲取一些數據。 然后,對於該數據數組中的每個元素,我正在向不同的端點發出另一個請求(因此使用“forkJoin”運算符)。 所有請求都一次發送,但它們似乎仍然一個接一個地執行,而不是同時執行。
this.sites$.subscribe(data => {
// data.forEach(element => {
// this.siteCaptureMap[element.id] = new CaptureData();
// this.sitesService.getCaptureData(element.nameOrNumber, element.owner.name).subscribe(data => {
// this.siteCaptureMap[element.id].count = data.length;
// });
// });
var obs: Observable<any>[] = [];
for (var _i = 0; _i < data.length; _i++) {
this.siteCaptureMap[data[_i].id] = new CaptureData();
this.siteCaptureMap[data[_i].id].id = _i;
obs.push(this.sitesService.getCaptureData(data[_i].nameOrNumber, data[_i].owner.name));
}
forkJoin(obs).subscribe(results => {
for (var _i = 0; _i < results.length; _i++) {
this.siteCaptureMap[data[_i].id].count = results[_i].length;
}
});
this.dataSource.data = data;
this.dataSource.filteredData = data;
});
再次,任何幫助將不勝感激。 如果我需要澄清任何事情或提供任何其他代碼片段,請告訴我! 謝謝!
嵌套的subscribe
可能會導致 memory 泄漏,並且很難取消訂閱,因此每當您嵌套了subscribe
時,請考慮switchMap
、 concatMap
和mergeMap
。
它們都有微小的變化,但它們從以前的 observable 切換到新的 observable。 這篇 文章解釋了這些差異。
對你來說,我會嘗試做:
import { switchMap } from 'rxjs/operators';
...
this.sites$.pipe(
switchMap(data => {
let obs: Observable<any>[] = [];
for (let _i = 0; _i < data.length; _i++) {
this.siteCaptureMap[data[_i].id] = new CaptureData();
this.siteCaptureMap[data[_i].id].id = _i;
obs.push(this.sitesService.getCaptureData(data[_i].nameOrNumber, data[_i].owner.name));
}
return forkJoin(obs);
}),
).subscribe(results => {
for (let_i = 0; _i < results.length; _i++) {
this.siteCaptureMap[data[_i].id].count = results[_i].length;
}
this.dataSource.data = data;
this.dataSource.filteredData = data;
});
附帶說明是使用let
和const
而不是var
。
此外,如果您看到所有請求同時發出,這就是您所希望的。 如果它連續返回,則可能是瀏覽器或服務器造成的。
首先,我將重新排列代碼以使其更符合 rxjs 的習慣,刪除嵌套訂閱並使用pipe
並使其更具功能風格。 內聯注釋試圖解釋變化
this.sites$.pipe(
// this is the rxjs map operator that transform the data received from
// the rest api into something different
map(data => {
// I create the obs array using the map method of JS arrays - this is
// NOT the rxjs map operator
obs = data.map((element, _i) => {
this.siteCaptureMap[element.id] = new CaptureData();
this.siteCaptureMap[element.id].id = _i;
return this.sitesService.getCaptureData(element.nameOrNumber, element.owner.name)
});
// return both the array of observables and the data
return [data, obs];
}),
// concatMap makes sure that you wait for the completion of the rest api
// call and the emission of the data fetched before you execute another
// async operation via forkJoin
concatMap(([data, obs]) => forkJoin(obs).pipe(
// this is the rxjs map operator used to return not only the results
// received as result of forkJoin, but also the data received with the
// first rest call - I use this operator to avoid having to define
// a variable where to store 'data' and keep the logic stateless
map(results => ([data, results]))
))
).subscribe(([data, results]) => {
// here I use forEach to loop through the results and perform
// your logic
results.forEach((res, _i) => this.siteCaptureMap[data[_i].id].count = res.length)
})
我覺得這個表格更符合rxjs及其功能精神,應該和你原來的表格是等價的。
同時,我很想知道您為什么說您的代碼當時在forkJoin
one 中執行調用。
順便說一句,如果您有興趣查看 rxjs 和 http 的常見使用模式,您可以閱讀這篇文章。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.