将可观察的有效载荷拆分为多个可观察的

Posted

技术标签:

【中文标题】将可观察的有效载荷拆分为多个可观察的【英文标题】:Splitting observable payload into multiple observables 【发布时间】:2021-10-13 17:55:30 【问题描述】:

我有一个 Apollo 查询,我通过一个 map 操作符来发送对象。例如,name: "doron", color: "red"

query$ = this.apollo.watchQuery(query)

我想将其拆分为 2 个可观察对象 - name$color$,以便 name$ 发出名称值,color$ 发出颜色值。

我们今天要做的是:

name$ = new Subject();
color$ = new Subject();
query$.valueChanges.subscribe(p => 
  name$.next(p.name);
  color$.next(p.color);
)

这并不理想,因为我们需要手动取消订阅。此外,它在订阅任何“子”可观察对象之前订阅查询。

如何在不订阅查询的情况下执行此操作?

【问题讨论】:

【参考方案1】:

不要将部分 observables 创建为 Subjects 并推送给它们,而是通过从查询映射直接创建它们。

name$ = query.valueChanges.pipe(map((name) => name));
color$ = query.valueChanges.pipe(map((color) => color));

然后您可以轻松地单独取消订阅它们或在async 管道中使用它们。我创建了一个小展示来说明它是如何工作的:Demo

【讨论】:

当我们订阅每个 observable 时会发生什么?那不会触发两次查询吗? 您正在订阅valueChanges,订阅它不会触发更改。所以很安全【参考方案2】:

您可以分享 OQ observable 并使用 pluck 获取您的价值

const oq = query$.valueChanges.pipe(share());

let name$ = oq.pipe(pluck('name'));
let color$ = oq.pipe(pluck('color'))

【讨论】:

虽然这是一个很好的解决方案,但问题是如果你有 Typescript,它不是类型安全的(据我所知),另一方面,@dallows 是类型安全的 pluck 或使用 map 并不能确保运行时的类型安全。 Typescript 仅在编译时保护类型。所以为了 100% 类型安全,我们必须添加类型检查功能 你是对的,我的错。我以为地图会改变类型 再看我不认为我错了,看看this StackBlitz,当主题是数字类型而不是字符串时它会出错,你也可以看看maphere的源代码 我知道,这就是我的意思,编译时间,这就是为什么我说如果你有打字稿会很有用,就我而言,pluck 不提供那种类型安全【参考方案3】:

虽然 Fan 和 Dallows 都有很好的答案,但我认为两者结合 + 稍作调整会很好:

query$ = query.pipe(
  // You won't subscribe to `query` twice (or more).
  shareReplay(

    // If one of the observables (`query$`, `name$` or `color$`) are subscribed to later on,
    // you'll get instantly the last value that was emitted 
    // (compared to `share` which wouldn't give you the last value if you subscribe too late).
    bufferSize: 1,

    // Whenever the number of subscribers to the query falls down to 0, it'll automatically unsubscribe from that observable as well.
    refCount: true
  )
);

name$ = query$.valueChanges.pipe(
  map((name) => name)
);
color$ = query$.valueChanges.pipe(
  map((color) => color)
);

(下面的解释也写成上面代码的注释)

使用shareReplay,您不会订阅query 两次(或更多)。

感谢bufferSize: 1,如果稍后订阅了其中一个可观察对象(query$name$color$),您将立即获得发出的最后一个值(与 share 相比)如果您订阅得太晚,它不会给您最后的价值)。

感谢refCount: true,每当查询的订阅者数量降至 0 时,它也会自动取消订阅该 observable。

【讨论】:

以上是关于将可观察的有效载荷拆分为多个可观察的的主要内容,如果未能解决你的问题,请参考以下文章

将可观察响应映射为 Angular 中的自定义接口数组

RxSwift:将可完成映射到单个可观察?

RxSwift 将可观察对象数组与对象数组结合

如何将可观察集合绑定到 xamarin 中的 flexlayout?

如何将可观察对象发布的整数变量绑定到 SwiftUI 中的 textField?

如何将可观察值传递给@Input() Angular 4