Angular 中的主题 vs 行为主题 vs ReplaySubject

IT技术 javascript angular rxjs reactive-programming angular2-observables
2021-01-21 11:06:36

我一直在寻找理解这 3 点:

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

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

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

谢谢

6个回答

这真的归结为行为和语义。用一个

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

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

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

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

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

所以这真的归结为您期望的行为(至于使用哪个)。大多数情况下,您可能想要使用 a,BehaviorSubject因为您真正想要表示的是“随时间变化的value”语义。但我个人认为用ReplaySubject初始化的替换没有任何问题1

当您真正需要的是一些缓存行为时,您想要避免的是使用 vanilla Subject以您正在编写路由保护或解析为例。您在该守卫中获取一些数据并将其设置在服务中Subject然后在路由组件中订阅服务主题以尝试获取在守卫中发出的值。面向对象。value在哪里?它已经发出了,呃。使用“缓存”主题!

也可以看看:

缓冲区为 1 的 ReplaySubject 与 BehaviorSubject 的不同之处在于 ReplaySubject 将阻止订阅者等待第一个值,而 BehaviorSubject 在创建时需要一个初始值。通常,您希望按需延迟获取数据并且没有任何初始值。
2021-03-20 11:06:36
我认为您可以为重播主题提及的一个非常简单的示例是“聊天室”或游戏大厅场景,您希望新加入者看到最后 10 条消息。
2021-03-30 11:06:36
这是简短且易于理解的差异。当服务中的值更改并且组件也更改显示值时,那么 BehaviourSubjects 或 Replay Subject 是解决方案。
2021-04-04 11:06:36
谢谢!ReplaySubject缓冲区大小为 1 正是我所需要的。我有一个需要该值的路由守卫,但需要等待第一次发射。所以 aBehaviorSubject没有削减它,因为我不想要一个初始值(null也不起作用,因为我用它来表示一个状态)
2021-04-07 11:06:36
“如果你ReplaySubject用 1 的缓冲区大小初始化 a ,那么它实际上就像一个BehaviorSubject:这不完全正确;查看这篇很棒的博客文章了解两者之间的差异。例如,如果您订阅了 Completed BehaviorSubject,您将不会收到最后一个值,但对于 aReplaySubject(1)您将收到最后一个值。
2021-04-11 11:06:36

不同可观察类型的方便总结,我知道的非直观命名哈哈

  • Subject - 订阅者只会在订阅后获得已发布的值。
  • BehaviorSubject - 新订阅者在订阅后立即获得最后发布的值或初始值。
  • ReplaySubject - 新订阅者在订阅后立即获得所有先前发布的值
@JasonCheng 不,它在订阅时检索所有以前发布的值,更新答案:)
2021-03-28 11:06:36
1-n 个已发布的值?所以如果有 2 个发布的值,一个 ReplaySubject 会产生 -1 个发布的值???
2021-04-04 11:06:36
  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);

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

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

请注意迟到的订阅如何错过推送到主题中的一些数据。

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

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

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);
});

这是在控制台上为我们提供的内容:

From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
  1. Behavior subject:类似于重播主题,但只会重新发出最后发出的值,如果之前没有发出任何值,则为默认值:
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);
});

结果:

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

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

参考文章真的很有帮助
2021-03-30 11:06:36

大多数赞成的答案显然是错误的,声称:

“如果你ReplaySubject用 1 的缓冲区大小初始化 a ,那么它实际上就像一个BehaviorSubject


这并不完全正确。查看这篇很棒的博客文章了解两者之间的差异。例如,如果您订阅了 Completed BehaviorSubject,您将不会收到最后一个值,但对于 aReplaySubject(1)您将收到最后一个值。

这是一个不容忽视的重要区别:

const behavior = new BehaviorSubject(null);
const replay = new ReplaySubject(1);

behavior.skip(1).subscribe(v => console.log('BehaviorSubject:', v));
replay.subscribe(v => console.log('ReplaySubject:', v));

behavior.next(1);
behavior.next(2);
behavior.complete();
behavior.subscribe(v => console.log('Late B subscriber:', v));

replay.next(1);
replay.next(2);
replay.complete();
replay.subscribe(v => console.log('Late R subscriber:', v));

在此处查看此代码示例示例来自关于该主题的另一篇很棒的博客文章

来自:Randall Koutnik 的书“用 RxJS 构建react式网站”。

一个主题是一个对象,是一个涡轮增压观察到。就其核心而言,Subject 的行为很像一个常规的 observable,但每个订阅都连接到同一个源。主体也是观察者,并且有 next、error 和 done 方法可以一次向所有订阅者发送数据。因为主体是观察者,所以它们可以直接传递到 subscribe 调用中,来自原始 observable 的所有事件都将通过主体发送给其订阅者。

我们可以使用ReplaySubject来跟踪历史。一个ReplaySubject记录最后n个事件和发挥他们回到每一个新用户。例如在聊天应用程序中。我们可以用它来跟踪以前的聊天记录。

BehaviorSubject是的简化版本ReplaySubjectReplaySubject存储的事件的任意数,BehaviorSubject只记录最新事件的value。每当BehaviorSubject记录新订阅时,它都会向订阅者发出最新值以及传入的任何新值。BehaviorSubject在处理单个状态单元(例如配置选项)时很有用。