Observable vs Subject 和 asObservable
Posted
技术标签:
【中文标题】Observable vs Subject 和 asObservable【英文标题】:Observable vs Subject and asObservable 【发布时间】:2018-08-02 18:51:26 【问题描述】:我正在学习 RxJs,我正在寻求对我的假设的确认或更正。
我正在尝试在服务中使 public read only 可观察,我可以在我的服务类的各个位置使用.next()
。我想知道这是否是正确的方法:
private myObservable = new Subject<T>();
public myObservable$: Observable<T> = this.myObservable.asObservable();
用户可以订阅myObservable$
我可以用myObservable.next(...);
它工作得很好,但我有足够的经验知道我可能只是一个不知情的白痴(RxJS 很大)。对于所述用例,这是正确的模式和正确的对象吗?
【问题讨论】:
是的,这是一种常见且正确的模式。但在许多情况下,它是不需要的。如果您需要向非绑定的组件发送通知,您只需要一个主题。如果你正在绑定,Angular 的变更检测可以处理通知。我有一个主题/行为主题和匹配代码的示例,这里没有它具有相同的功能:github.com/DeborahK/MovieHunter-communication(MH-Take4 和 MH-Take5) @DeborahK 根据该线程中一些回复的一些 cmets,我很好奇您对在 TypeScript 中使用 private 有何想法。是否应该不使用 private 编写代码,因为它实际上不是私有的,是否应该像在编写 C# 一样在 typescript 中编写代码并且简单地忽略 transpile 将私有和公共视为相同的事实? TypeScript 的全部意义在于通过为我们提供类型、接口和可访问性关键字(例如private
)来为我们提供编码帮助/生产力。如果我们不打算使用这些东西……使用 TypeScript 就没有意义了。所有这些都被转译出来的事实并不重要。在某个时刻,这一切都变成了 1 和 0。 :-)
你是对的。 TypeScript 提供了更高的 开发时间 抽象......它实际上对运行时没有任何作用。
@DeborahK 正如其设计者所说,typescript 的目的是为 javascript 的隐式类型系统提供静态可验证的形式化。切线地,当使用各种框架的程序员希望假装它描述了一个类似 Java 的类型系统时,这个错误是迄今为止在 Angular 社区中最常见的。长期以来,许多开发人员都不愿意学习 JavaScript,认为 TypeScript 提供了 JavaScript 的 替代 是严重错误的。凭借您在 JS 方面的背景以及作为教育工作者的角色,您无疑知道这一点。
【参考方案1】:
你所做的是正确的。然而,仍然有一个更短的符号。由于 Subject 已经是一个 Observable(它继承了 Observable 类),您可以将类型检查留给 TypeScript:
private myObservable = new Subject<T>();
public myObservable$: Observable<T> = this.myObservable;
您服务的任何消费者都可以订阅myObservable$
,但不能调用myObservable$.next()
,因为TypeScript 不允许您这样做(Observable 类没有任何next()
方法)。
这实际上是推荐的方式,RxJS 内部从不使用asObservable
。更详细的讨论见:
https://github.com/ReactiveX/rxjs/pull/2408
https://github.com/ReactiveX/rxjs/issues/2391
看到一个非常相似的问题:Should rxjs subjects be public in the class?
【讨论】:
正确的第二行是myObservable$ = myObservable.asObservable();
,它根本没有next
方法,也是Observable<T>
的类型
Observable<T>
类型由 TypeScript 强制执行。您可以避免它的唯一方法是使用您通常从不使用的(myObservable$ as any).next()
。阅读两个 GitHub 链接,为什么 RxJS 内部总是使用这种方式。
好吧,这有点苛刻,但这是一种虚假的安全感。问题是人们倾向于忘记类型断言不是强制转换,因为它们看起来像强制转换。无论如何,你有 RX Js 人支持你,尽管其中一个人非常不同意。
如果你真的担心安全问题,我也建议你使用getter来接收Observable
。否则有人可能会用他自己的Subject
覆盖它并开始推送不需要的数据。
标准方法是使用asObservable
,它不提供next
。那些github
链接与图书馆的消费者无关,这是一个内部微优化讨论。函数式响应式编程中使用的第三方库(例如 ramda)在组合过程中经常会丢失类型信息,因此如果不是 asOvservable
,仍然可以调用 next
【参考方案2】:
在项目中,我们正在使用这种 Observables,这为您提供了对私有 observable 的适当封装,但您仍然可以使用一些公共方法调用 next()
。
private sourceName = new Subject<T>();
name = this.sourceProductName.asObservable();
sendName(item: T)
this.sourceName.next(item);
【讨论】:
您使用了 BehaviorSubject,在我的用例中我不需要它。并添加了一个公共方法,从而否定了广播的封装。 没关系,你可以用Subject
替换它,我有时用它来在一段时间内用 getValue()
检索这个 Observable 的值,它会满足你的需要。
对不起,我编辑并留下了初始值,Subject
不需要。
您确实复制了我的代码,然后通过向私有变量添加公共方法访问器以删除封装来破坏它。我想你可能误解了这个问题。如果您阅读了您的代码,则可以将其替换为name = new Subject<T>();
,那么您确实保护了除next()
之外的所有内容,基于此,我认为您只是误读了我的帖子。我认为这归结为:我在我的 OP 中的假设是正确的。但是谢谢你帮我戳了戳。
@EddieMarinaro 通过private
没有隐私之类的东西,所以这很难被破坏。我同意简单地包装该方法毫无意义。 asObservable
的重点是隐藏主题,但它是另一种隐藏方式以上是关于Observable vs Subject 和 asObservable的主要内容,如果未能解决你的问题,请参考以下文章
RXJS 中 Observable 和 Subject 的异同
rxSwift 中的 observable 和 subject 有啥区别