Angular 中的 Subject vs BehaviorSubject vs ReplaySubject

新手上路,请多包涵

我一直在寻找了解这三个:

我想使用它们,知道何时以及为什么使用它们,使用它们有什么好处,尽管我已经阅读了文档、观看了教程并搜索了谷歌,但我对此没有任何理解。

那么他们的目的是什么?一个真实的案例将是最值得赞赏的,它甚至不需要编码。

我更喜欢一个清晰的解释,而不仅仅是“a+b => c 你订阅了……”

谢谢

原文由 user6015054 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 719
2 个回答

它真的归结为行为和语义。与

  • Subject - 订阅者只会获得订阅 发出的发布值。问问自己,这是你想要的吗?订户是否需要了解有关先前值的任何信息?如果没有,那么你可以使用这个,否则选择其他之一。例如,组件到组件的通信。假设您有一个组件,可以在单击按钮时为其他组件发布事件。您可以使用具有主题的服务进行通信。

  • BehaviorSubject - 最后一个值被缓存。订阅者将在初始订阅时获得最新值。该主题的语义是表示随时间变化的值。例如登录用户。初始用户可能是匿名用户。但是一旦用户登录,新值就是经过身份验证的用户状态。

BehaviorSubject 用初始值初始化。这有时对编码偏好很重要。比如说你用 null 初始化它。然后在您的订阅中,您需要进行空检查。也许还好,也许很烦人。

  • ReplaySubject - 它最多可以缓存指定数量的发射。任何订阅者都将在订阅时获得所有缓存的值。你什么时候需要这种行为?老实说,我不需要这样的行为,除了以下情况:

如果您初始化 ReplaySubject 的缓冲区大小为 1 ,那么它实际上 表现 得就像 BehaviorSubject 。最后一个值总是被缓存,所以它就像一个随时间变化的值。有了这个,就不需要 null 检查就像 --- 用 null BehaviorSubject 初始化一样在这种情况下,在第一次发布之前,不会向订阅者发送任何值。

所以它真的归结为您期望的行为(至于使用哪一个)。大多数时候您可能想要使用 BehaviorSubject 因为您真正想要表示的是“随时间推移的价值”语义。但我个人认为用 ReplaySubject 初始化的 1 的替换没有任何问题。

当您真正需要的是一些缓存行为时,您要 避免 使用 vanilla Subject 。举个例子,你正在写一个路由守卫或一个解决方案。您在该守卫中获取一些数据并将其设置在服务中 Subject 。然后在路由组件中,您订阅服务主题以尝试获取在守卫中发出的值。哎呀。价值在哪里?它已经发出了,DUH。使用“缓存”主题!

也可以看看:

原文由 Paul Samsotha 发布,翻译遵循 CC BY-SA 4.0 许可协议

  1. 主题:在订阅时,它总是获取订阅后推送的数据,即 _未收到以前推送的值_。
 const mySubject = new Rx.Subject();

mySubject.next(1);

const subscription1 = mySubject.subscribe(x => {
  console.log('From subscription 1:', x);
});

mySubject.next(2);

const subscription2 = mySubject.subscribe(x => {
  console.log('From subscription 2:', x);
});

mySubject.next(3);

subscription1.unsubscribe();

mySubject.next(4);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>

在这个例子中,这是将打印在控制台中的结果:

 From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4

请注意迟到的订阅是如何丢失一些被推送到主题中的数据的。

  1. 重播主题:可以通过保留将发送给新订阅 的先前值的缓冲区 来提供帮助。

这是重播主题的使用示例,其中 buffer of 2 previous values 被保留并在新订阅中发出:

 const mySubject = new Rx.ReplaySubject(2);

mySubject.next(1);
mySubject.next(2);
mySubject.next(3);
mySubject.next(4);

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>

这是在控制台上给我们的:

 From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5

  1. 行为主题:类似于重播主题,但将仅重新发出最后发出的值,或者如果之前没有发出任何值,则返回默认值:
 const mySubject = new Rx.BehaviorSubject('Hey now!');

mySubject.subscribe(x => {
  console.log('From 1st sub:', x);
});

mySubject.next(5);

mySubject.subscribe(x => {
  console.log('From 2nd sub:', x);
});
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.12/Rx.min.js"></script>

结果:

 From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5

参考: https ://alligator.io/rxjs/subjects/

原文由 Varun Sukheja 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题