热和冷可观察量:是否有 'hot' 和 'cold' 运算符?
Hot and Cold observables: are there 'hot' and 'cold' operators?
我查看了以下 SO 问题:
What are the Hot and Cold observables?
总结一下:
- 冷可观察对象在有观察者使用它们时发出其值,即观察者接收到的值序列与订阅时间无关。所有观察者都将使用相同的值序列。
- 热可观察对象独立于其订阅发出值,即观察者收到的值是订阅时间的函数。
然而,我觉得热与冷仍然是一个混乱的根源。所以这是我的问题:
默认情况下所有 rx observables 都是冷的吗(受试者除外)?
我经常读到事件是热可观察量的典型隐喻,但我也读到 Rx.fromEvent(input, 'click')
是冷可观察量(?)。
there/what 是将冷 observable 转换为热 observable 的 Rx 运算符吗(publish
和 share
除外)?
例如,它如何与 Rx 运算符一起工作 withLatestFrom
?让 cold$
成为一个已在某处订阅的冷可观察对象。 sth$.withLatestFrom(cold$,...)
会成为一个热门的可观察对象吗?
或者如果我 sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
并订阅 sth1
和 sth2
,我是否总是会看到 sth
的相同值?
我认为 Rx.fromEvent
会创建冷可观察对象,但事实并非如此,如其中一个答案所述。但是,我仍然对这种行为感到困惑:https://codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个可观察对象中获得不同的值。 click
活动没有分享吗?
这不是您所有问题的答案(我想知道所有问题!)但是可以肯定的是,所有 fromEvent
Observables 都是热门的。 Click 似乎不是因为它不是像 mousemove 这样的 "continous" 事件,但无论如何订阅源(addEventListener
或 on
调用)仅在创建 Observable 时完成一次。所以很热。您可以在运算符 here and there 的源代码中看到它 - 创建的可观察对象是 share
d,无论事件名称或来源是什么。
values
在你的 codepen 中是懒惰的 - 在订阅之前什么都不会发生,此时它会运行并连接起来。因此,在您的示例中,尽管您订阅了同一个变量,但它正在创建两个不同的流;每个订阅电话一个。
您可以将 values
视为附加了 map
的 click
的流生成器。
该地图末尾的 .share()
会产生我们预期的行为,因为它是隐式订阅。
您的总结和链接的问题都是正确的,我认为术语可能会让您感到困惑。我建议您将热和冷可观察量分别视为主动和被动可观察量。
也就是说,无论是否有人订阅,活动(热)可观察对象都会发出项目。再一次,典型的例子是,无论是否有人在听,按钮点击事件都会发生。这种区别很重要,因为例如,如果我单击一个按钮然后订阅按钮单击(按此顺序),我将看不到已经发生的按钮单击。
被动(冷)可观察对象将等到订阅者存在后才会发出项目。想象一个按钮,在有人监听事件之前你不能点击它——这将确保你总是看到每一个点击事件。
默认情况下所有 Rx observables 都是 "cold"(或被动)吗?不,例如 Rx.fromEvent(input, 'click')
是一个热的(或活跃的)可观察对象。
I also read that Rx.fromEvent(input, 'click')
is a cold observable(?)
事实并非如此。
Are there Rx operators which turn a cold observable into a hot observable?
将热(主动)可观察对象转变为冷(被动)可观察对象的概念是:您需要记录在没有任何订阅时发生的事件,并(以各种方式)向订阅者提供这些项目将来一起。一种方法是使用 Subject。例如,您可以使用 ReplaySubject
来缓冲发出的项目并将它们重播给未来的订阅者。
您指定的两个运算符(publish
和 share
)都在内部使用主题来提供该功能。
How does it work with Rx operator withLatestFrom
? Let cold$
be a cold observable which has been subscribed to. Will something$.withLatestFrom(cold$,...)
be a hot observable?
如果 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 to foo
and bar
, will I always see the same values for both?
不总是。同样,如果 foo
和 bar
是点击不同的按钮,那么您会看到不同的值。同样,即使它们是相同的按钮,如果您的组合函数(withLatest
的第二个参数)对于相同的输入没有 return 相同的结果,那么您将不会看到相同的值(因为它会被调用两次,如下所述)。
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 the click
event shared?
我会向您指出 我有过关于相同行为的问题。这个答案会比我更好地解释它,但它的要点是源(点击事件)是 "shared",是的,但你对它的操作不是。如果您不仅要共享点击事件,还要共享其上的操作,则需要明确地这样做。
几个月后我会回到我原来的问题,同时想分享获得的知识。
我将使用以下代码作为解释支持(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(){});
如其中一个答案所述,定义一个可观察对象会导致一系列回调和参数注册。必须启动数据流,这是通过 subscribe
函数完成的。
之后可以找到详细流程(为了说明而简化)。
Observables 默认是冷的。订阅一个可观察对象将导致上游订阅链发生。最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者。
该观察者依次向下一个观察者发送数据,从而产生下游数据流,直至接收器观察者。下面的简化图显示了两个订阅者订阅同一个可观察对象时的订阅和数据流。
可以通过使用主题或通过 multicast
运算符(及其派生词,请参阅下面的注释 3)来创建热可观察对象。
引擎盖下的 multicast
运算符使用一个主题和 returns 一个可连接的可观察对象。所有对运算符的订阅都将是对内部主题的订阅。当 connect
被调用时,内部 subject 订阅上游 observable,数据流向下游。
主题在内部操作订阅的观察者列表并将传入数据多播给所有订阅的观察者。
下图总结了情况。
归根结底,理解观察者模式导致的数据流和算子的实现更重要
例如,如果obs
很热,那么hotOrCold = obs.op1
是冷还是热?无论答案是什么:
- 如果
obs.op1
没有订阅者,则不会有数据流经 op1
。如果有 hot obs
的订阅者,这意味着 obs.op1
可能会丢失数据
- 假设
op1
不是 multicast-like 运算符,订阅两次 hotOrCold
将订阅两次 op1
,并且来自 obs
的每个值将两次流过 op1
.
备注:
- 此信息应该对 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
更新 :另请参阅 the following articles, here, and there) 关于 Ben Lesh 的主题。
有关主题的更多详细信息可以在另一个 SO 问题中找到:
我查看了以下 SO 问题: What are the Hot and Cold observables?
总结一下:
- 冷可观察对象在有观察者使用它们时发出其值,即观察者接收到的值序列与订阅时间无关。所有观察者都将使用相同的值序列。
- 热可观察对象独立于其订阅发出值,即观察者收到的值是订阅时间的函数。
然而,我觉得热与冷仍然是一个混乱的根源。所以这是我的问题:
默认情况下所有 rx observables 都是冷的吗(受试者除外)?
我经常读到事件是热可观察量的典型隐喻,但我也读到
Rx.fromEvent(input, 'click')
是冷可观察量(?)。there/what 是将冷 observable 转换为热 observable 的 Rx 运算符吗(
publish
和share
除外)?例如,它如何与 Rx 运算符一起工作
withLatestFrom
?让cold$
成为一个已在某处订阅的冷可观察对象。sth$.withLatestFrom(cold$,...)
会成为一个热门的可观察对象吗?或者如果我
sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
并订阅sth1
和sth2
,我是否总是会看到sth
的相同值?我认为
Rx.fromEvent
会创建冷可观察对象,但事实并非如此,如其中一个答案所述。但是,我仍然对这种行为感到困惑:https://codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个可观察对象中获得不同的值。click
活动没有分享吗?
这不是您所有问题的答案(我想知道所有问题!)但是可以肯定的是,所有 fromEvent
Observables 都是热门的。 Click 似乎不是因为它不是像 mousemove 这样的 "continous" 事件,但无论如何订阅源(addEventListener
或 on
调用)仅在创建 Observable 时完成一次。所以很热。您可以在运算符 here and there 的源代码中看到它 - 创建的可观察对象是 share
d,无论事件名称或来源是什么。
values
在你的 codepen 中是懒惰的 - 在订阅之前什么都不会发生,此时它会运行并连接起来。因此,在您的示例中,尽管您订阅了同一个变量,但它正在创建两个不同的流;每个订阅电话一个。
您可以将 values
视为附加了 map
的 click
的流生成器。
.share()
会产生我们预期的行为,因为它是隐式订阅。
您的总结和链接的问题都是正确的,我认为术语可能会让您感到困惑。我建议您将热和冷可观察量分别视为主动和被动可观察量。
也就是说,无论是否有人订阅,活动(热)可观察对象都会发出项目。再一次,典型的例子是,无论是否有人在听,按钮点击事件都会发生。这种区别很重要,因为例如,如果我单击一个按钮然后订阅按钮单击(按此顺序),我将看不到已经发生的按钮单击。
被动(冷)可观察对象将等到订阅者存在后才会发出项目。想象一个按钮,在有人监听事件之前你不能点击它——这将确保你总是看到每一个点击事件。
默认情况下所有 Rx observables 都是 "cold"(或被动)吗?不,例如 Rx.fromEvent(input, 'click')
是一个热的(或活跃的)可观察对象。
I also read that
Rx.fromEvent(input, 'click')
is a cold observable(?)
事实并非如此。
Are there Rx operators which turn a cold observable into a hot observable?
将热(主动)可观察对象转变为冷(被动)可观察对象的概念是:您需要记录在没有任何订阅时发生的事件,并(以各种方式)向订阅者提供这些项目将来一起。一种方法是使用 Subject。例如,您可以使用 ReplaySubject
来缓冲发出的项目并将它们重播给未来的订阅者。
您指定的两个运算符(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?
如果 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
和 bar
是点击不同的按钮,那么您会看到不同的值。同样,即使它们是相同的按钮,如果您的组合函数(withLatest
的第二个参数)对于相同的输入没有 return 相同的结果,那么您将不会看到相同的值(因为它会被调用两次,如下所述)。
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?
我会向您指出
几个月后我会回到我原来的问题,同时想分享获得的知识。 我将使用以下代码作为解释支持(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(){});
如其中一个答案所述,定义一个可观察对象会导致一系列回调和参数注册。必须启动数据流,这是通过 subscribe
函数完成的。
之后可以找到详细流程(为了说明而简化)。
Observables 默认是冷的。订阅一个可观察对象将导致上游订阅链发生。最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者。
该观察者依次向下一个观察者发送数据,从而产生下游数据流,直至接收器观察者。下面的简化图显示了两个订阅者订阅同一个可观察对象时的订阅和数据流。
可以通过使用主题或通过 multicast
运算符(及其派生词,请参阅下面的注释 3)来创建热可观察对象。
引擎盖下的 multicast
运算符使用一个主题和 returns 一个可连接的可观察对象。所有对运算符的订阅都将是对内部主题的订阅。当 connect
被调用时,内部 subject 订阅上游 observable,数据流向下游。
主题在内部操作订阅的观察者列表并将传入数据多播给所有订阅的观察者。
下图总结了情况。
归根结底,理解观察者模式导致的数据流和算子的实现更重要
例如,如果obs
很热,那么hotOrCold = obs.op1
是冷还是热?无论答案是什么:
- 如果
obs.op1
没有订阅者,则不会有数据流经op1
。如果有 hotobs
的订阅者,这意味着obs.op1
可能会丢失数据 - 假设
op1
不是 multicast-like 运算符,订阅两次hotOrCold
将订阅两次op1
,并且来自obs
的每个值将两次流过op1
.
备注:
- 此信息应该对 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
更新 :另请参阅 the following articles, here, and there) 关于 Ben Lesh 的主题。
有关主题的更多详细信息可以在另一个 SO 问题中找到: