如何将可观察到的属性添加到第二个可观察的属性?

发布于 2025-01-22 20:42:31 字数 1398 浏览 5 评论 0原文

我正在尝试将可观察到的地址添加到可观察的用户。

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. 为什么用户$订阅没有地址对象?
  2. 为什么第一个点击执行并显示第二个点击似乎没有执行时显示地址对象?
  3. Concatmap是正确的映射操作员吗?

a “ nofollow noreferrer”> stackblitz 在此处提供。

I am trying to add an address Observable to a user Observable.

export interface Address {
 country: string;
 state: string;
 city: string;
 street: string;
 zipCode: number;
}

export interface User {
 id: number;
 name: string;
 address?: Address;
}

The operative code is:

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

Several questions:

  1. Why doesn't the user$ subscription have an address Object?
  2. Why does the first tap execute and show an address object while the second tap does not appear to execute?
  3. Is concatMap the proper mapping operator?

A StackBlitz is provided here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

请止步禁区 2025-01-29 20:42:31

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

问题中的代码与Stackblitz中的代码有一些显着差异。有了您的问题中的代码,它 do 具有地址对象。使用Stackblitz中的代码,其没有地址对象的原因是您仅使用getUser(index)而没有修改。您在73上定义了一个看起来像映射功能的函数,但是您没有将其传递到MAP

为什么第一个点击执行并显示第二个点击似乎没有执行的地址对象?

第二个点击在自己的行上,而不是管道的一部分。调用TAP自己做得太多。 IT(和其他操作员)返回了您希望修改的可观察到的行为的描述,但是您需要将其传递到.pipe中以创建新的观察值。

condmap是正确的映射操作员吗?

您的情况很简单(所有源可观察物都是同步的,只发出一个值)SwitchMap,concatmap和Mergemap都会产生相同的结果。对于更复杂的情况,多个值随时间分布,这就是不同的区别:

con缩图:当源可观察到的第一个值发射时,我们开始在第一个映射的可观察到。在我们继续前进的源可观察的第二个值之前,必须完成第一个可观察到的。当您需要确保一切按确切顺序发生,而没有任何早期终止时,ConcatMap就很有用。但是,如果您的观察力永无止境,这将阻止其他可观察到的跑步。

SwitchMap:发出第一个值时,我们开始在第一个映射的可观察到。只要源没有更多的值,这将持续下去,但是一旦从源中发出新值,我们将取消第一个映射的可观察到的值,然后切换到第二个。在新值表明我们需要停止工作并重新开始的情况下,SwitchMap很有用。

Mergemap:任何时候发出值时,我们也会在其映射的可观察到。多个映射的可观察物将以任何恰好到达的顺序发出值,而不会取消任何顺序。当您不关心订单时,Mergemap就很有用,并且只想按照它们到达的顺序进行处理。

Why doesn't the user$ subscription have an address Object?

The code in your question has some significant differences from the code in the stackblitz. With the code in your question, it does have an address object. With the code in the stackblitz, the reason it doesn't have an address object is that you're just using getUser(index) with no modification. You define a function on 73 that looks like a mapping function, but you aren't passing it into map

Why does the first tap execute and show an address object while the second tap does not appear to execute?

The second tap is on its own line, and not part of a pipe. Calling tap on its own doesn't do much. It (and other operators) returns a description of how you want the modified observable to behave, but you then need to pass that into .pipe to create the new observable.

Is concatMap the proper mapping operator?

Your case is simple enough (all the source observables are synchronous and emit only one value) that switchMap, concatMap, and mergeMap would all have the same result. For more complicated cases where multiple values are spread out in time, here's the difference:

concatMap: When the first value is emitted by the source observable, we begin work on the first mapped observable. That first observable must complete before we can move on to the second value of the source observable. concatMap is useful when you need to guarantee that everything happens in an exact order, and nothing terminates early. But if you have observables that never end, this will block other observables from ever running.

switchMap: When the first value is emitted, we begin work on the first mapped observable. This will continue as long as there are no more values from the source, but once a new value is emitted from the source, we will cancel the first mapped observable and switch to the second one. switchMap is useful in cases where a new value is an indication that we need to stop our work and start over.

mergeMap: Any time a value is emitted, we will work on its mapped observable too. Values will be emitted by the multiple mapped observables in whatever order they happen to arrive, and nothing will ever be cancelled. mergeMap is useful when you don't care about order, and just want to process things as soon as they arrive, in the order they arrive.

方觉久 2025-01-29 20:42:31

基于您更新的stackblitz,您未在最终可观察到的地址中未包含的地址的原因是因为您没有在subscribe中添加数据

//before
users$.subscribe((/*no Data from the source*/) => console.log(users))

//after
users$.subscribe((withAddress) => console.log(withAddress))

Base on your updated Stackblitz, the reason you were not getting the address included in the final observable is because you didn't add the data within the subscribe

//before
users$.subscribe((/*no Data from the source*/) => console.log(users))

//after
users$.subscribe((withAddress) => console.log(withAddress))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文