[英]Angular/ RxJS: nested service calls with observables
I'm new to RxJS observables and I'm trying to resolve a rather simple use case. 我是RxJS可观察对象的新手,正在尝试解决一个相当简单的用例。
In a service, I first make a http call that returns an item (as an observable). 在服务中,我首先进行http调用,以返回一个项目(作为可观察的对象)。 The item contains an array of ids, some of them repeated.
该项目包含ID数组,其中一些重复。 For each distinct id, I need to call another http service (again returns an observable), and add its return value to the original item in place of the corresponding id.
对于每个不同的ID,我需要调用另一个http服务(再次返回一个observable),并将其返回值添加到原始项目中,以代替相应的ID。 These calls should happen in parallel.
这些调用应并行进行。 Finally, once every call has completed, my service should return an observable of the original item, now with its sub-items in place.
最后,每次通话结束后,我的服务应返回可观察到的原始项目,现在已包含其子项目。
To give a better idea, this is what it would look like with promises rather than observables: 为了给出更好的主意,这是用promise而不是可观察的东西看起来的样子:
MyService() {
return HttpGetMainItem()
.then(item => {
var promises = _.uniq(item.subItems)
.map(sid => HttpGetSubItem(sid)
.then(subItem => {
// add to matching item.subItems
}));
// wait for all promises to complete and return main item
return Promise.all(promises).then(() => item);
});
}
What would be the best way to accomplish this working with observables? 用可观察物完成此工作的最佳方法是什么?
EDIT: from the answers it seems I wasn't very clear. 编辑:从答案看来我不是很清楚。 The example with promises is just for clarity, in my case the http calls are actually Angular's HttpClient.get, so they return observables- I'm looking to do everything with observables.
带有promises的示例只是为了清楚起见,在我的情况下,http调用实际上是Angular的HttpClient.get,因此它们返回的是observables-我正在寻找使用observables做的所有事情。
Here's one way you can accomplish the above with rxjs. 这是使用rxjs完成上述操作的一种方法。
from
. from
将promise转换为可观察的。 switchMap
so that you can call another observable and return that as the result of the outer observable. switchMap
以便您可以调用另一个可观察对象,并将其作为外部可观察对象的结果返回。 You're switching execution contexts. forkJoin
to create an Observable of all the elements' promise. forkJoin
创建所有元素的诺言的Observable。 ForkJoin will emit an array of all the results once all promise complete. promise.all
. promise.all
。 Code 码
from(HttpGetMainItem()).pipe(
switchMap(item =>
forkJoin(_.uniq(item.subItems).map(sid => HttpGetSubItem(sid)))
.pipe(
map(results => {
/* add results to matching items.subItems and */
return item;
})
)
)
);
I feel this looks a bit clunky, due to the need to retain the root item and the nesting it requires. 我觉得这有点笨拙,因为需要保留根项目及其所需的嵌套。 You can use the selector parameter of switchMap to combine the outer and inner observable.
您可以使用switchMap的选择器参数来组合外部和内部可观察对象。 You can use that parameter in place of the logic you had in
map()
and since both observables' results are passed you won't need any further nesting. 您可以使用该参数来代替您在
map()
使用的逻辑,并且由于两个可观察对象的结果都已传递,因此您不需要任何进一步的嵌套。
from(HttpGetMainItem()).pipe(
switchMap(
item => forkJoin(_.uniq(item.subItems).map(sid => HttpGetSubItem(sid))),
(item, results) => {
/* add results to matching items.subItems and */
return item;
}
)
);
I believe you need something like this: 我相信您需要这样的东西:
import { from, forkJoin } from 'rxjs';
import { switchMap } from 'rxjs/operators';
itemWithSubItems$ = from(HttpGetMainItem()).pipe(
switchMap(item => {
const promises = _.uniq(item.subItems).map(item => HttpGetSubItem(item.sid));
return forkJoin(promises)
.map(resultArray => item.subItems = resultArray)
.map(_ => item);
})
);
First fetches the main item. 首先获取主要项目。 Then use forkJoin to resolve all subqueries and enrich the main item.
然后使用forkJoin解决所有子查询并充实主要项目。 After that just return the main item.
之后,只需返回主要项目即可。
Maybe you could use a lib like async.each -> https://caolan.github.io/async/docs.html#each (eachSeries maybe). 也许您可以使用像async.each-> https://caolan.github.io/async/docs.html#each (可能是eachSeries)之类的库。
would be something like : 就像这样:
async.each(array, (obj, cb) => {
observable with obj in parameter and with subscriber result :
cb(err, subscriberRes);
}, (err, res) => {
console.log(res);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.