【问题标题】:Observable vs Subject and asObservableObservable vs Subject 和 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 方面的背景以及作为教育工作者的角色,您无疑知道这一点。

标签: javascript angular typescript rxjs angular-services


【解决方案1】:

你所做的是正确的。然而,仍然有一个更短的符号。由于 Subject 已经是一个 Observable(它继承了 Observable 类),您可以将类型检查留给 TypeScript:

private myObservable = new Subject<T>();
public myObservable$: Observable<T> = this.myObservable;

您服务的任何消费者都可以订阅myObservable$,但不能调用myObservable$.next(),因为TypeScript 不允许您这样做(Observable 类没有任何next() 方法)。

这实际上是推荐的方式,RxJS 内部从不使用asObservable。更详细的讨论见:

看到一个非常相似的问题:Should rxjs subjects be public in the class?

【讨论】:

  • 正确的第二行是myObservable$ = myObservable.asObservable();,它根本没有next 方法,也是Observable&lt;T&gt; 的类型
  • Observable&lt;T&gt; 类型由 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&lt;T&gt;();,那么您确实保护了除next() 之外的所有内容,基于此,我认为您只是误读了我的帖子。我认为这归结为:我在我的 OP 中的假设是正确的。但是谢谢你帮我戳了戳。
  • @EddieMarinaro 通过private 没有隐私之类的东西,所以这很难被破坏。我同意简单地包装该方法毫无意义。 asObservable 的重点是隐藏主题,但它是另一种隐藏方式
猜你喜欢
  • 1970-01-01
  • 2018-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-29
  • 1970-01-01
相关资源
最近更新 更多