javascript Hot 和 Cold observables:是否有“hot”和“cold”运算符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32190445/
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
Hot and Cold observables: are there 'hot' and 'cold' operators?
提问by user3743222
I reviewed the following SO question: What are the Hot and Cold observables?
我回顾了以下 SO 问题: Hot 和 Cold observables 是什么?
To summarize:
总结一下:
- a cold observable emits its values when it has an observer to consume them, i.e. the sequence of values received by observers is independent of time of subscription. All observers will consume the same sequence of values.
- a hot observable emits value independently of its subscriptions, i.e. the values received by observers are a function of the time of subscription.
- 当一个冷的 observable 有一个观察者来消费它们时,它会发出它的值,即观察者接收到的值的序列与订阅时间无关。所有观察者都将使用相同的值序列。
- 热 observable 发出与其订阅无关的值,即观察者接收到的值是订阅时间的函数。
Yet, I feel like hot vs. cold is still a source of confusion. So here are my questions:
然而,我觉得热与冷仍然是混淆的根源。所以这里是我的问题:
Are all rx observables cold by default (with the exception of subjects)?
I often read that events are the typical metaphor for hot observables, but I also read that
Rx.fromEvent(input, 'click')
is a cold observable(?).Are there/what are the Rx operators which turn a cold observables into a hot observable (apart from
publish
, andshare
)?For instance, how does it work with Rx operator
withLatestFrom
? Letcold$
be a cold observable which has somewhere been subscribed to. Willsth$.withLatestFrom(cold$,...)
be a hot observable?Or if I do
sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
and subscribe tosth1
andsth2
, will I always see the same value for bothsth
?I thought
Rx.fromEvent
creates cold observables but that is not the case, as mentioned in one of the answers. However, I am still baffled by this behaviour: https://codepen.io/anon/pen/NqQMJR?editors=101. Different subscriptions get different values from the same observable. Wasn't theclick
event shared?
默认情况下所有 rx observables 都是冷的(主体除外)?
我经常读到事件是热可观察的典型隐喻,但我也读到它
Rx.fromEvent(input, 'click')
是冷可观察(?)。是否有/什么 Rx 操作符可以将冷的 observable 变成热的 observable(除了
publish
, 和share
)?例如,它如何与 Rx 运算符一起工作
withLatestFrom
?让我们cold$
成为一个已在某处订阅的冷 observable。会sth$.withLatestFrom(cold$,...)
是一个热门的 observable 吗?或者,如果我
sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
订阅并订阅了sth1
andsth2
,我是否总是会看到两者的值相同sth
?Rx.fromEvent
正如其中一个答案中提到的那样,我认为会产生冷的可观察量,但事实并非如此。但是,我仍然对这种行为感到困惑:https: //codepen.io/anon/pen/NqQMJR?editors =101。不同的订阅从同一个 observable 获得不同的值。click
事件不是共享的吗?
回答by user3743222
I am coming back a few months later to my original question and wanted to share the gained knowledge in the meanwhile. I will use the following code as an explanation support (jsfiddle):
几个月后我又回到了我原来的问题,同时想分享所获得的知识。我将使用以下代码作为解释支持(jsfiddle):
var ta_count = document.getElementById('ta_count');
var ta_result = document.getElementById('ta_result');
var threshold = 3;
function emits ( who, who_ ) {return function ( x ) {
who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n");
};}
var messages$ = Rx.Observable.create(function (observer){
var count= 0;
setInterval(function(){
observer.onNext(++count);
}, 1000)
})
.do(emits(ta_count, 'count'))
.map(function(count){return count < threshold})
.do(emits(ta_result, 'result'))
messages$.subscribe(function(){});
As mentioned in one of the answers, defining an observable leads to a series of callback and parameter registration. The data flow has to be kicked in, and that is done via the subscribe
function.
A (simplified for illustration) detailed flow can be find thereafter.
正如其中一个答案中提到的,定义一个 observable 会导致一系列回调和参数注册。必须启动数据流,这是通过subscribe
函数完成的。之后可以找到(为了说明而简化)详细流程。
Observables are cold by default. Subscribing to an observable will result in an upstream chain of subscriptions taking place. The last subscription leads to the execution of a function which will handle a source and emit its data to its observer.
默认情况下,Observable 是冷的。订阅 observable 将导致发生订阅的上游链。最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者。
That observer in its turn emits to the next observer, resulting in a downstream flow of data, down to the sink observer. The following simplified illustration shows subscription and data flows when two subscribers subscribe to the same observable.
该观察者依次向下一个观察者发送数据,从而产生下游数据流,直至下沉观察者。下面的简化图显示了当两个订阅者订阅同一个 observable 时的订阅和数据流。
Hot observables can be created either by using a subject, or through the multicast
operator (and its derivatives, see Note 3 below).
可以通过使用主题或通过multicast
运算符(及其派生词,请参见下面的注释 3)来创建热可观察对象。
The multicast
operator under the hood makes use of a subject and returns a connectable observable. All subscriptions to the operator will be subscriptions to the inner subject. When connect
is called, the inner subject subscribes to the upstream observable, and data flows downstream.
Subjects manipulate internally a list of subscribed observers and multicast incoming data to all subscribed observers.
在multicast
引擎盖下运营商利用一个主题,并返回一个可连接的可观察的。对运营商的所有订阅都将是对内部主题的订阅。当connect
被调用时,内部主体订阅上游可观察对象,数据流向下游。主体在内部操作订阅观察者的列表,并将传入数据多播给所有订阅的观察者。
The following diagram summarizes the situation.
下图总结了这种情况。
In the end, it matters more to understand the flow of data caused by the observer pattern and the implementation of the operators.
最后,更重要的是理解观察者模式导致的数据流和运算符的实现。
For instance, if obs
is hot, is hotOrCold = obs.op1
cold or hot? Whatever the answer is :
例如,如果obs
是热的,是hotOrCold = obs.op1
冷的还是热的?不管答案是什么:
- if there are no subscribers to
obs.op1
, no data will flow throughop1
. If there were subscribers to hotobs
, that meansobs.op1
will have possibly lost pieces of data - supposing that
op1
is not a multicast-like operator, subscribing twice tohotOrCold
will subscribe twice toop1
, and every value fromobs
will flow twice throughop1
.
- 如果没有订阅者
obs.op1
,则没有数据流过op1
。如果有订阅者到 hotobs
,那意味着obs.op1
可能会丢失一些数据。 - 假设它
op1
不是类似多播的运算符,订阅两次 tohotOrCold
将订阅两次op1
,并且每个值 fromobs
将流过两次op1
。
Notes :
注意事项:
- This information should be valid for Rxjs v4. While the version 5 has gone through considerable changes, most of it still applies verbatim.
- Unsubscription, error and completion flows are not represented, as they are not in the scope of the question. Schedulers are also not taken into account. Among other things, they influence the timing of the data flow, but a priori not its direction and content.
- According to the type of subject used for multicasting, there are different derived multicasting operators:
- 此信息应该对 Rxjs v4 有效。虽然第 5 版经历了相当大的变化,但其中大部分仍然适用。
- 取消订阅、错误和完成流程未表示,因为它们不在问题的范围内。调度程序也不考虑在内。除其他外,它们影响数据流的时间,但先验地不影响其方向和内容。
- 根据用于组播的主题类型,有不同的派生组播算子:
Subject type | `Publish` Operator | `Share` operator
------------------ | --------------------------- | -----------------
Rx.Subject | Rx.Observable.publish | share
Rx.BehaviorSubject | Rx.Observable.publishValue | shareValue
Rx.AsyncSubject | Rx.Observable.publishLast | N/A
Rx.ReplaySubject | Rx.Observable.replay | shareReplay
Subject type | `Publish` Operator | `Share` operator
------------------ | --------------------------- | -----------------
Rx.Subject | Rx.Observable.publish | share
Rx.BehaviorSubject | Rx.Observable.publishValue | shareValue
Rx.AsyncSubject | Rx.Observable.publishLast | N/A
Rx.ReplaySubject | Rx.Observable.replay | shareReplay
Update: See also the following articles, here, and there) on that subject by Ben Lesh.
更新:另请参阅本·莱什 (Ben Lesh)撰写的有关该主题的以下文章 (here和 there)。
Further details on subjects can be found in this other SO question : What are the semantics of different RxJS subjects?
有关主题的更多详细信息可以在另一个 SO 问题中找到:不同 RxJS 主题的语义是什么?
回答by Whymarrh
Your summary, and the linked question are both correct, I think the terminology may be confusing you. I propose you think of hot and cold observables as active and passive observables (respectively).
您的总结和链接的问题都是正确的,我认为这些术语可能会让您感到困惑。我建议您将热和冷 observables 视为主动和被动 observables(分别)。
That is, an active (hot) observable will be emitting items whether someone has subscribed or not. The canonical example, again, button click events happen whether someone is listening to them or not. This distinction is important because, if, for example, I click a button and then subscribe to button clicks (in that order), I will not see the button click that has already happened.
也就是说,无论是否有人订阅,活动(热)可观察对象都会发出项目。再举一个规范的例子,无论有人是否在听,按钮点击事件都会发生。这种区别很重要,因为,例如,如果我单击一个按钮然后订阅按钮点击(按该顺序),我将看不到已经发生的按钮点击。
A passive (cold) observable will wait until a subscriber exists before emitting items. Imagine a button where you cannot click on it until someone is listening to the events—this would ensure that you always see each and every click event.
被动(冷) observable 将等到订阅者存在后再发出项目。想象一个按钮,在有人监听事件之前你不能点击它——这将确保你总是看到每一个点击事件。
Are all Rx observables "cold" (or passive) by default? No, Rx.fromEvent(input, 'click')
for example is a hot (or active) observable.
默认情况下,所有 Rx 可观察对象都是“冷的”(或被动的)吗?不,Rx.fromEvent(input, 'click')
例如是一个热(或活跃)的可观察对象。
I also read that
Rx.fromEvent(input, 'click')
is a cold observable(?)
我还读到这
Rx.fromEvent(input, 'click')
是一个冷的 observable(?)
That is not the case.
事实并非如此。
Are there Rx operators which turn a cold observable into a hot observable?
是否有 Rx 操作符可以将冷的 observable 变成热的 observable?
The concept of turning a hot (active) observable into a cold (passive) observable is this: you need to record the events that happen while nothing is subscribed and offer those items (in various ways) to subscribers that come along in the future. One way to do this is to use a Subject. For example, you could use a ReplaySubject
to buffer up items emitted and replay them to future subscribers.
将热(主动)可观察对象转变为冷(被动)可观察对象的概念是:您需要记录在没有订阅任何内容时发生的事件,并将这些项目(以各种方式)提供给将来出现的订阅者。一种方法是使用Subject。例如,您可以使用 aReplaySubject
来缓冲发出的项目并将它们重播给未来的订阅者。
The two operators you named (publish
and share
) both use subjects internally to offer that functionality.
您命名的两个运算符 (publish
和share
) 都在内部使用主题来提供该功能。
How does it work with Rx operator
withLatestFrom
? Letcold$
be a cold observable which has been subscribed to. Willsomething$.withLatestFrom(cold$,...)
be a hot observable?
它如何与 Rx 运算符一起使用
withLatestFrom
?让我们cold$
成为一个已订阅的冷 observable。会something$.withLatestFrom(cold$,...)
是一个热门的 observable 吗?
If something
is a hot observable, then yes. If something
is a cold observable, then no. Going back to the events example, if something
is a stream of button click events:
如果something
是一个热可观察对象,那么是的。如果something
是冷可观察对象,则不是。回到事件示例,如果something
是按钮单击事件流:
var clickWith3 = Rx.fromEvent(input, 'click')
.withLatest(Rx.Observable.from([1, 2, 3]);
Or if I do
foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)
and subscribe tofoo
andbar
, will I always see the same values for both?
或者,如果我
foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)
订阅并订阅foo
andbar
,我是否总是会看到两者的相同值?
Not always. Again, if foo
and bar
are clicks on different buttons for example, then you would see different values. As well, even if they were the same button, if your combination function (the 2nd argument to withLatest
) does not return the same result for the same inputs, then you would not see the same values (because it would be called twice, as explained below).
不总是。同样,例如,如果foo
和bar
是单击不同的按钮,那么您将看到不同的值。同样,即使它们是同一个按钮,如果您的组合函数( 的第二个参数withLatest
)没有为相同的输入返回相同的结果,那么您将不会看到相同的值(因为它会被调用两次,如解释以下)。
I thought
Rx.fromEvent
creates cold observables but that is not the case, as mentioned in one of the answers. However, I am still baffled by this behaviour: codepen.io/anon/pen/NqQMJR?editors=101. Different subscriptions get different values from the same observable. Wasn't theclick
event shared?
Rx.fromEvent
正如其中一个答案中提到的那样,我认为会产生冷的可观察量,但事实并非如此。但是,我仍然对这种行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个 observable 获得不同的值。click
事件不是共享的吗?
I'll point you to this great answer by Enigmativityto a question I had about the same behaviour. That answer will explain it a lot better than I can, but the gist of it is that the source (the click event) is "shared", yes, but your operations on it are not. If you want to share not just the click event but also the operation on it, you will need to do so explicitly.
我会向您指出Enigmativity对我对相同行为提出的问题的这个很好的答案。这个答案会比我能更好地解释它,但它的要点是源(点击事件)是“共享的”,是的,但你对它的操作不是。如果您不仅要共享单击事件,还要共享对它的操作,则需要明确地这样做。
回答by electrichead
values
in your codepen is lazy - nothing happens until something subscribes, at which point it runs through and wires it up. So in your example, although you are subscribing to the same variable, it is creating two different streams; one for each subscribe call.
values
在您的 codepen 中是惰性的 - 直到某些东西订阅之后才会发生任何事情,此时它会运行并连接它。所以在你的例子中,虽然你订阅了同一个变量,但它创建了两个不同的流;每个订阅调用一个。
You can think of values
as being a generator of streams for click
with that map
attached.
你可以认为values
作为流的生成click
与map
附着。
.share()
on the end of that map would create the behaviour we expect, because it is implicitly subscribing.
.share()
在该地图的末尾将创建我们期望的行为,因为它是隐式订阅。
回答by Eryk Napiera?a
It's not an answer for all your questions (I would like to know all of them!) but for sure, all fromEvent
Observables are hot. Click seems to be not because it's not "continous" event like mousemove, but anyway subscription to the source (addEventListener
or on
call) is done only once, when Observable is created. So it's hot. You can see it in source code of the operator hereand there- created observable is share
d no matter what is the event name or source.
这不是您所有问题的答案(我想知道所有问题!)但可以肯定的是,所有fromEvent
Observable 都很热门。Click 似乎不是因为它不是像 mousemove 这样的“连续”事件,但无论如何订阅源(addEventListener
或on
调用)只在创建 Observable 时完成一次。所以很热。你可以在这里和那里在操作符的源代码中看到它-share
无论事件名称或来源是什么,创建的 observable 都是d。