展平嵌套的Observable

时间:2016-11-06 02:27:31

标签: javascript angular rxjs observable rxjs5

我陷入了嵌套的可观察地狱,可以用手做。

我有以下代码块

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>[]>

我认为我可以用map替换最初的flatMap,但这会将对象转换为<Observable<Observable<User>>

RxJS文档有点难以破译,所以我不确定switchforkJoinflatMap的哪种组合可以让我得到我需要的东西。

我希望返回Observable<User[]>。有人能指出我正确的方向吗?

2 个答案:

答案 0 :(得分:6)

实际上,您不需要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()将高阶Observable转换为单个observable。在这种情况下,它接受所有用户的数组并逐个重新发出它们。然后,mergeMap()会使用last_login日期更新用户。最后,我使用toArray()将单个用户转换为一个整体发出的大型数组(如果您想要发出单个用户,则可以删除此运算符)。

请注意,当您使用return users.map(...)时,您使用Array.map()返回一个数组,而不是来自返回Observable的RxJS的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 } ]

答案 1 :(得分:2)

一种解决方案是使用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;
  }
));