Flattening nested Observables

前端 未结 2 1590
梦毁少年i
梦毁少年i 2020-12-19 01:42

I\'m a stuck in nested observable hell and could do with a hand.

I have the following block of code

return this.findUser(term).map( users => {
  r         


        
相关标签:
2条回答
  • 2020-12-19 02:21

    Actually, you don't need forkJoin() nor switch() to do this.

    In general, you want to update each user in the array of users by another async call.

    I'd do it like this:

    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));
    

    Operator mergeAll() converts a higher-order Observable into single observables. In this case it takes the array of all users and re-emits them one by one. Then mergeMap() emits users updated with the last_login date. At the end I used toArray() to transform single users into one large array that is them emitted as whole (you can remove this operator if you want to emit single users instead).

    Note that when you used return users.map(...) you were using Array.map() that returns an array and not map() from RxJS that returns an Observable. I think working with single objects is usually easier that with arrays of objects.

    See live demo: https://jsbin.com/naqudun/edit?js,console

    This prints to 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 } ]
    
    0 讨论(0)
  • 2020-12-19 02:47

    One solution would be to use forkJoin to join and then map the results of calls to getLastLogin to users:

    // 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;
      }
    ));
    
    0 讨论(0)
提交回复
热议问题