Javascript Angular 中的主题 vs 行为主题 vs ReplaySubject
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43118769/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Subject vs BehaviorSubject vs ReplaySubject in Angular
提问by Paul Samsotha
I've been looking to understand those 3:
我一直在寻找理解这 3 点:
Subject, Behavior subjectand Replay subject. I would like to use them and know when and why, what are the benefits of using them and although I've read the documentation, watched tutorials and searched google I've failed to make any sense of this.
主题、行为主题和回放主题。我想使用它们并知道何时以及为什么使用它们有什么好处,尽管我已经阅读了文档、观看了教程并在谷歌上搜索过,但我对此一无所知。
So what are their purpose? A real-world case would be most appreciated it does not have to even code.
那么他们的目的是什么?一个真实世界的案例将是最值得赞赏的,它甚至不必编码。
I would prefer a clean explanation not just "a+b => c you are subscribed to ...."
我更喜欢简洁的解释,而不仅仅是“a+b => c 你订阅了……”
Thank you
谢谢
回答by Paul Samsotha
It really comes down to behavior and semantics. With a
这真的归结为行为和语义。用一个
Subject- a subscriber will only get published values that were emitted afterthe subscription. Ask yourself, is that what you want? Does the subscriber need to know anything about previous values? If not, then you can use this, otherwise choose one of the others. For example, with component-to-component communication. Say you have a component that publishes events for other components on a button click. You can use a service with a subject to communicate.BehaviorSubject- the last value is cached. A subscriber will get the latest value upon initial subscription. The semantics for this subject is to represent a value that changes over time. For example a logged in user. The initial user might be an anonymous user. But once a user logs in, then the new value is the authenticated user state.The
BehaviorSubjectis initialized with an initial value. This is sometimes important to coding preference. Say for instance you initialize it with anull. Then in your subscription, you need to do a null check. Maybe OK, or maybe annoying.ReplaySubject- it can cache up to a specified number of emissions. Any subscribers will get all the cached values upon subscription. When would you need this behavior? Honestly, I have not had any need for such behavior, except for the following case:If you initialize a
ReplaySubjectwith a buffer size of1, then it actually behavesjust like aBehaviorSubject. The last value is always cached, so it acts like a value changing over time. With this, there is no need for anullcheck like in the case of theBehaviorSubjectinitialized with anull. In this instance, no value is ever emitted to the subscriber until the first publishing.
Subject- 订阅者只会获得订阅后发出的已发布值。问问自己,这是你想要的吗?订阅者是否需要了解以前的值?如果没有,那么您可以使用它,否则选择其他之一。例如,使用组件到组件的通信。假设您有一个组件,它在单击按钮时为其他组件发布事件。您可以使用具有主题的服务进行通信。BehaviorSubject- 最后一个值被缓存。订阅者将在初始订阅时获得最新值。该主题的语义是表示随时间变化的值。例如登录用户。初始用户可能是匿名用户。但是一旦用户登录,新值就是经过身份验证的用户状态。将
BehaviorSubject被初始化为一个初始值。这有时对编码偏好很重要。比如说你用一个null. 然后在您的订阅中,您需要进行空检查。也许还好,也许烦人。ReplaySubject- 它可以缓存指定数量的排放。任何订阅者都将在订阅时获得所有缓存的值。你什么时候需要这种行为?老实说,我没有任何需要这种行为,除了以下情况:如果
ReplaySubject使用缓冲区大小初始化 a1,那么它实际上的行为就像 aBehaviorSubject。最后一个值总是被缓存,所以它就像一个随时间变化的值。有了这个,就不需要null像BehaviorSubject用 a 初始化的情况那样进行检查了null。在这种情况下,在第一次发布之前,不会向订阅者发送任何值。
So it really comes down to the behavior you are expecting (as for which one to use). Most of the time you will probably want to use a BehaviorSubjectbecause what you really want to represent is that "value over time" semantic. But I personally don't see anything wrong with the substitution of ReplaySubjectinitialized with 1.
所以这真的归结为您期望的行为(至于使用哪个)。大多数情况下,您可能想要使用 a ,BehaviorSubject因为您真正想要表示的是“随时间变化的价值”语义。但我个人认为用ReplaySubject初始化的替换没有任何问题1。
What you want to avoidis using the vanilla Subjectwhen what you really need is some caching behavior. Take for example you are writing a routing guard or a resolve. You fetch some data in that guard and set it in a service Subject. Then in the routed component you subscribe to the service subject to try to get that value that was emitted in the guard. OOPs. Where's the value? It was already emitted, DUH. Use a "caching" subject!
当您真正需要的是一些缓存行为时,您要避免使用香草Subject。例如,您正在编写路由保护或解析。您在该守卫中获取一些数据并将其设置在服务中Subject。然后在路由组件中订阅服务主题以尝试获取在守卫中发出的值。面向对象。价值在哪里?它已经发出了,呃。使用“缓存”主题!
See also:
也可以看看:
回答by Ricky Boyce
A handy summary of the different observable types, non intuitive naming i know lol.
不同可观察类型的方便总结,我知道的非直观命名,哈哈。
Subject- A subscriber will only get published values thereon-after the subscription is made.BehaviorSubject- New subscribers get the last published value OR initial value immediately upon subscription.ReplaySubject- New subscribers get the last1-npublished value(s) immediately upon subscription (only if previously emitted).
Subject- 订阅者只会在订阅后获得已发布的值。BehaviorSubject- 新订阅者在订阅后立即获得最后发布的值或初始值。ReplaySubject- 新订阅者1-n在订阅后立即获得最后发布的值(仅在之前发布的情况下)。
回答by Varun Sukheja
- Subject: On subscribing it always gets the data which is pushed after it's subscription i.e. previous pushed values are not received.
- 主题:订阅时,它总是获取订阅后推送的数据,即未收到之前推送的值。
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);
With this example, here's the result that'll be printed in the console:
在这个例子中,这是将在控制台中打印的结果:
From subscription 1: 2
From subscription 1: 3
From subscription 2: 3
From subscription 2: 4
Note how subscriptions that arrive late are missing out on some of the data that's been pushed into the subject.
请注意迟到的订阅如何错过推送到主题中的一些数据。
- Replay subjects: can help by keeping a buffer of previous valuesthat will be emitted to new subscriptions.
- 重播主题:可以通过保留将发送给新订阅的先前值的缓冲区来提供帮助。
Here's a usage example for replay subjects where a buffer of 2 previous valuesare kept and emitted on new subscriptions:
这是重播主题的使用示例,其中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);
});
Here's what that gives us at the console:
这是在控制台上为我们提供的内容:
From 1st sub: 3
From 1st sub: 4
From 1st sub: 5
From 2nd sub: 4
From 2nd sub: 5
- Behavior subjects: are similar to replay subjects, but will re-emit only the last emitted value, or a default value if no value has been previously emitted:
- 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);
});
And the result:
结果:
From 1st sub: Hey now!
From 1st sub: 5
From 2nd sub: 5
Reference: https://alligator.io/rxjs/subjects/
回答by H S Progr
From: Randall Koutnik book “Build Reactive Websites with RxJS.” :
来自:Randall Koutnik 的书“用 RxJS 构建反应式网站”。:
A Subjectis an object that's a turbocharged observable. At its core, a Subjectacts much like a regular observable, but each subscription is hooked into the same source. Subjectsalso are observers and have next, error, and done methods to send data to all subscribers at once. Because subjectsare observers, they can be passed directly into a subscribe call, and all the events from the original observable will be sent through the subject to its subscribers.
一个主题是一个对象,是一个涡轮增压观察到。就其核心而言,Subject 的行为很像一个常规的 observable,但每个订阅都连接到同一个源。主体也是观察者,并且有 next、error 和 done 方法可以一次向所有订阅者发送数据。因为主体是观察者,所以它们可以直接传递到 subscribe 调用中,来自原始 observable 的所有事件都将通过主体发送给其订阅者。
We can use the ReplaySubjectto track history. A ReplaySubjectrecords the last n events and palys them back to every new subscriber. For example in chat application. We can use it for tracking the record of previous chat history.
我们可以使用ReplaySubject来跟踪历史。一个ReplaySubject记录最后n个事件和palys他们回到每一个新用户。例如在聊天应用程序中。我们可以用它来跟踪以前的聊天记录。
A BehaviorSubjectis a simplified version of the ReplaySubject. The ReplaySubjectstored an arbitrary number of events, the BehaviorSubjectonly records the value of the latest event. Whenever a BehaviorSubjectrecords a new subscription, it emits the latest value to the subscriber as well as any new values that are passed in. The BehaviorSubjectis useful when dealing with single units of state, such as configuration options.
甲BehaviorSubject是的简化版本ReplaySubject。该ReplaySubject存储的事件的任意数,BehaviorSubject只记录最新事件的价值。每当BehaviorSubject记录新订阅时,它都会向订阅者发出最新值以及传入的任何新值。BehaviorSubject在处理单个状态单元(例如配置选项)时很有用。
回答by Pramod Patil
// ***********Subject concept ***********
let subject = new Subject<string>();
subject.next("Eureka");
subject.subscribe((data) => {
console.log("Subscriber 1 got data >>>>> "+ data);
});
subject.subscribe((data) => {
console.log("Subscriber 2 got data >>>>> "+ data);
});
// ********behaviour subject*********
// Behavior subjects need a first value
let subject1 = new BehaviorSubject<string>("First value");
subject1.asObservable().subscribe((data) => {
console.log("First subscriber got data behaviour subject>>>>> "+ data);
});
subject1.next("Second value")
- Subject - A subscriber will only get published values thereon-after the subscription is made.
- BehaviorSubject - New subscribers get the last published value OR initial value immediately upon subscription.
- 主题 - 订阅者只会在订阅后获得已发布的值。
- BehaviorSubject - 新订阅者在订阅后立即获得最后发布的值或初始值。
回答by Wilt
Most upvoted answer is plainly wrong claiming that:
大多数赞成的答案显然是错误的,声称:
"If you initialize a ReplaySubjectwith a buffer size of 1, then it actually behaves just like a BehaviorSubject"
“如果你ReplaySubject用 1 的缓冲区大小初始化 a ,那么它实际上就像一个BehaviorSubject”
This is not totally true; check this great blog poston differences between those two. For example if you subscribe to a completed BehaviorSubject, you won't receive the last value but for a ReplaySubject(1)you will receive the last value.
这并不完全正确。查看这篇很棒的博客文章,了解这两者之间的差异。例如,如果您订阅了 Completed BehaviorSubject,您将不会收到最后一个值,但对于 aReplaySubject(1)您将收到最后一个值。
This is am important difference that should not be overlooked:
这是一个不容忽视的重要区别:
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));
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));
Check this code example herewhich comes from another great blog poston the topic.

