扁平化嵌套的可观察对象

Flattening nested Observables

本文关键字:观察 对象 嵌套 扁平化      更新时间:2023-09-26

我被嵌套的可观察对象困住了,需要一只手。

我有以下代码块

return this.findUser(term).map( users => {
  return users.map( user => this.getLastLogin(user.user_id).map( last_login => {
    user.last_login = last_login;
    return user;
  }));
});

findUser返回Observable<User[]>, getLastLogin返回Observable<number>

我基本上希望获取一个用户列表,然后用另一个值的信息更新这个列表。

现在上面的代码返回<Observable<Observable<User>[]>

我想我可以用flatMap代替最初的map,但这会把对象变成<Observable<Observable<User>>

RxJS文档有点难以破译,所以我不确定switch, forkJoinflatMap的什么组合会让我得到我需要的。

我希望返回Observable<User[]>。谁能给我指个正确的方向?

实际上,您不需要forkJoin()switch()来完成此操作。

通常,您希望通过另一个异步调用来更新用户数组中的每个用户。

我想这样做:

var source = findUser('term')
    .mergeAll()
    .mergeMap(user => getLastLogin(user.user_id)
        .map(last_login => {
            user.last_login = last_login;
            return user;
        })
    )
    .toArray();
source.subscribe(val => console.log(val));

操作符mergeAll()将高阶可观察对象转换为单个可观察对象。在本例中,它获取所有用户的数组,并逐一重新发出它们。然后mergeMap()发出使用last_login日期更新的用户。最后,我使用toArray()将单个用户转换为一个大数组,该数组将它们作为整体发出(如果您想发出单个用户,则可以删除此操作符)。

注意,当你使用return users.map(...)时,你使用的是返回一个数组的Array.map(),而不是RxJS返回一个Observable的map()。我认为处理单个对象通常比处理对象数组更容易。

查看实时演示:https://jsbin.com/naqudun/edit?js,console

打印到控制台:

[ { name: 'foo',
    user_id: 42,
    last_login: 2016-11-06T10:28:29.314Z },
  { name: 'bar',
    user_id: 21,
    last_login: 2016-11-06T10:28:29.316Z } ]

一种解决方案是使用forkJoin加入,然后将调用getLastLogin的结果映射到用户:

// forkJoin will return Observable<User[]>, so use switchMap.
return this.findUser(term).switchMap(users => Observable.forkJoin(
  // Map the array of users to the array of observables to be joined. Use
  // first to ensure the observables complete.
  users.map(user => this.getLastLogin(user.user_id).first()),
  // Use forkJoin's selector to add the last_login to each user and return
  // the users.
  (...logins) => {
    users.forEach((user, index) => { user.last_login = logins[index]; });
    return users;
  }
));

正如@martin指出的,mergeAll()是解决方案。您也可以在map操作结束时应用它。

使用最新的语法,它读作:

getStations(factoryId: number): Observable<Station[]> {//...omitted}
getAllStations(): Observable<Station[]> {
const result =  this.factoriesService.getFactories().pipe(
  map(factories => factories.map(f => f.id)),
  mergeMap(factoryIds => factoryIds.map(id => this.getStations(id))),
  mergeAll()
);
return result;

}