我如何从一个可观察对象添加属性到第二个可观察对象?



我正在尝试添加一个地址可观察对象到用户可观察对象。

export interface Address {
country: string;
state: string;
city: string;
street: string;
zipCode: number;
}
export interface User {
id: number;
name: string;
address?: Address;
}

操作代码为:

// Observables - declaration
let users$: Observable<User[]>;
let address$: Observable<Address[]>;
// Observables - assignation
users$ = of(users);
address$ = of(address);
const getUser = (userId: number) => of(users[userId]);
users$ = address$.pipe(
switchMap((address: Address[]) => {
const userArray$: Observable<User>[] = [];
address.forEach((add, index) => {
const user$: Observable<User> = getUser(index).pipe(
map((user$) => ({...user$, address: add})),
tap(userArray$ => console.log('Alla',userArray$))
)
userArray$.push(user$)
tap(userArray$ => console.log('Allb',userArray$))  
})
return forkJoin(userArray$);
})

)
// Subscription
users$.subscribe(() => console.log(users))

若干问题:

  1. 为什么用户$ subscription没有地址对象?
  2. 为什么第一个tap执行并显示一个地址对象,而第二个tap似乎没有执行?
  3. concatMap是合适的映射操作符吗?

这里提供了一个StackBlitz

为什么用户$ subscription没有地址对象?

你的问题中的代码与stackblitz中的代码有一些显著的不同。使用问题中的代码,它确实有一个地址对象。对于stackblitz中的代码,它没有地址对象的原因是你只是使用getUser(index)而没有修改。您在73上定义了一个函数,看起来像一个映射函数,但您没有将其传递给map

为什么第一个tap执行并显示一个地址对象,而第二个tap似乎没有执行?

第二个tap在自己的行上,而不是pipe的一部分。单独调用tap并没有多大作用。它(和其他操作符)返回你想要修改的可观察对象的行为描述,但是你需要把它传递给.pipe来创建新的可观察对象。

concatMap是合适的映射操作符吗?

你的例子很简单(所有的源可观察对象都是同步的,并且只发出一个值),switchMap、concatMap和mergeMap都将有相同的结果。对于更复杂的情况(多个值在时间上分散),区别如下:

concatMap:当源可观察对象发出第一个值时,我们开始处理第一个映射的可观察对象。第一个可观察对象必须完成后,我们才能继续处理源可观察对象的第二个值。当您需要保证所有事情都按照精确的顺序发生,并且没有任何事情提前终止时,concatMap非常有用。但是如果你有一个永不结束的可观察对象,这将阻止其他可观察对象的运行。

switchMap:当发出第一个值时,我们开始处理第一个映射的可观察对象。只要源中没有更多的值,这个过程就会持续下去,但是一旦从源中发出了一个新值,我们就会取消第一个映射的可观察对象,并切换到第二个。当一个新值表示我们需要停止工作重新开始时,switchMap是很有用的。

mergeMap:任何时候发出一个值,我们也会处理它映射的可观察对象。值将由多个映射的可观察对象以它们碰巧到达的顺序发出,并且不会取消任何内容。当您不关心顺序,只想按照它们到达的顺序尽快处理它们时,mergeMap非常有用。

基于您更新的Stackblitz,您没有获得最终observable中包含的地址的原因是因为您没有在subscribe

中添加数据
//before
users$.subscribe((/*no Data from the source*/) => console.log(users))
//after
users$.subscribe((withAddress) => console.log(withAddress))

最新更新