我回顾了以下SO问题: What are the Hot and Cold observables?
总结:
然而,我觉得热和冷仍然是混乱的根源。所以这是我的问题:
默认情况下所有rx observable都是冷的(主题除外)?
我经常读到事件是热观察的典型隐喻,但我也读到Rx.fromEvent(input, 'click')
是冷可观察的(?)。
是否有/哪些Rx运算符将冷可观察量转换为热可观察量(publish
和share
除外)?
例如,它如何与Rx运算符withLatestFrom
一起使用?让cold$
成为一个冷的可观察者,它已被某个地方订阅。 sth$.withLatestFrom(cold$,...)
会成为热门观察者吗?
或者如果我sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
并订阅sth1
和sth2
,我是否会始终看到sth
的相同值?
我认为Rx.fromEvent
会产生冷可观察性,但事实并非如此,正如其中一个答案所述。但是,我仍然对这种行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个observable获得不同的值。我没有分享click
个活动吗?
答案 0 :(得分:71)
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(){});
如其中一个答案所述,定义一个observable会导致一系列回调和参数注册。必须启动数据流,这是通过subscribe
函数完成的。
此后可以找到(简化说明)详细流程。
默认情况下,Observable很冷。订阅可观察量将导致上游订阅链发生。最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者。
观察者轮流向下一个观察者发射,导致下游数据流向下到观察者。以下简化图示显示了当两个订阅者订阅相同的observable时的订阅和数据流。
可以通过使用主题或通过multicast
运算符(及其衍生词,参见下面的注释3)创建热观察值。
引擎盖下的multicast
运算符使用主题并返回可连接的observable。对运营商的所有订阅都将是对内部主题的订阅。当调用connect
时,内部主体订阅上游可观察者,数据流向下游。
主体在内部操纵订阅的观察者列表并将传入的数据多播到所有订阅的观察者。
下图总结了这种情况。
最后,理解由观察者模式和运营商实施引起的数据流更为重要。
例如,如果obs
很热,hotOrCold = obs.op1
是冷还是热?无论答案是什么:
obs.op1
没有订阅者,则数据不会流经op1
。如果有热门用户obs
,则表示obs.op1
可能会丢失数据op1
不是类似多播的运算符,则向hotOrCold
订阅两次将向op1
订阅两次,而来自obs
的每个值将在op1
中流过两次{ {1}}。注意:
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。
有关主题的更多详细信息可以在另一个SO问题中找到:What are the semantics of different RxJS subjects?
答案 1 :(得分:8)
您的摘要和相关问题都是正确的,我认为这个术语可能让您感到困惑。我建议你将冷热观测值分别视为主动和被动观测值。
也就是说,无论某人是否已订阅,活动(热)可观察者都将发出项目。再一次,按钮点击事件发生在规范的例子中,无论是否有人在听他们。这种区别很重要,因为,例如,如果我单击按钮然后订阅按钮点击(按此顺序),我将看不到已经发生的按钮点击。
被动(冷)可观察者将在发射物品之前等待用户存在。想象一个按钮,在有人听到事件之前你不能点击它 - 这样可以确保你总能看到每一个点击事件。
是否所有Rx可观察物和#34;冷&#34; (或被动)默认情况下?不,Rx.fromEvent(input, 'click')
例如是热(或活跃)可观察的。
我还读到
Rx.fromEvent(input, 'click')
是冷可观察的(?)
事实并非如此。
是否存在将冷观察变为热观测值的Rx算子?
将热(活动)可观察对象转换为冷(被动)可观察对象的概念是:您需要记录在没有订阅的情况下发生的事件,并将这些项目(以各种方式)提供给出现在中的订阅者未来。一种方法是使用Subject。例如,您可以使用ReplaySubject
缓冲发出的项目并将其重播给未来的订阅者。
您命名的两个运算符(publish
和share
)都在内部使用主题来提供该功能。
它如何与Rx运算符
withLatestFrom
一起使用?让cold$
成为已被订阅的冷可观察对象。something$.withLatestFrom(cold$,...)
会成为热门观察者吗?
如果something
是热门观察者,那么是。如果something
是冷可观察的,那么没有。回到事件示例,如果something
是按钮点击事件流:
var clickWith3 = Rx.fromEvent(input, 'click')
.withLatest(Rx.Observable.from([1, 2, 3]);
或者如果我
foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)
并订阅foo
和bar
,我是否会始终看到相同的值?
并非总是如此。同样,如果foo
和bar
是不同按钮上的点击,那么您会看到不同的值。同样,即使它们是相同的按钮,如果你的组合函数(withLatest
的第二个参数)没有为相同的输入返回相同的结果,那么你将看不到相同的值(因为它将是叫了两次,如下所述。
我认为
Rx.fromEvent
创造了冷可观察性,但事实并非如此,正如其中一个答案所述。但是,我仍然对这种行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个observable获得不同的值。我没有分享click
个活动吗?
我会指出this great answer by Enigmativity我对同一行为的问题。这个答案会比我能解释得更好,但它的要点是源(点击事件)是&#34;共享&#34;,是的,但你对它的操作不是。如果您不仅要共享click事件,还要共享其上的操作,则需要明确地共享。
答案 2 :(得分:4)
values
是懒惰的 - 在订阅之前没有任何事情发生,此时它会贯穿并连接起来。所以在你的例子中,虽然你订阅了同一个变量,但它创建了两个不同的流;每个订阅电话一个。
您可以将values
视为click
附加map
的流的生成器。
.share()
将创建我们期望的行为,因为它隐式订阅。