展平嵌套的 Observable
Flattening nested Observables
我被困在嵌套的可观察地狱中,需要帮助。
我有以下代码块
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
returns Observable<User[]>
和 getLastLogin
returns Observable<number>
.
我基本上希望获取用户列表,然后使用来自另一个值的信息更新它。
现在上面的代码是 returning <Observable<Observable<User>[]>
.
我想我可以用 flatMap
替换最初的 map
但这会将对象变成 <Observable<Observable<User>>
.
RxJS 文档有点难以解读,所以我不确定 switch
、forkJoin
或 flatMap
的哪种组合能让我得到我需要的东西。
我希望 return Observable<User[]>
。谁能指出我正确的方向?
一种解决方案是使用 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;
}
));
实际上,您不需要 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()
returns 一个数组,而不是 map()
来自 RxJS 的 returns 一个 Observable。我认为使用单个对象通常比使用对象数组更容易。
观看现场演示: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 } ]
我被困在嵌套的可观察地狱中,需要帮助。
我有以下代码块
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
returns Observable<User[]>
和 getLastLogin
returns Observable<number>
.
我基本上希望获取用户列表,然后使用来自另一个值的信息更新它。
现在上面的代码是 returning <Observable<Observable<User>[]>
.
我想我可以用 flatMap
替换最初的 map
但这会将对象变成 <Observable<Observable<User>>
.
RxJS 文档有点难以解读,所以我不确定 switch
、forkJoin
或 flatMap
的哪种组合能让我得到我需要的东西。
我希望 return Observable<User[]>
。谁能指出我正确的方向?
一种解决方案是使用 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;
}
));
实际上,您不需要 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()
returns 一个数组,而不是 map()
来自 RxJS 的 returns 一个 Observable。我认为使用单个对象通常比使用对象数组更容易。
观看现场演示: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 } ]