冷热观察者:有“热”和“冷”操作者吗?
我回顾了以下这个问题: 什么是热和冷的观察?
总结:
- 一个冷观察者在有观察者消耗它们的时候发出它的值,即观察者接收到的值序列与订阅时间无关。 所有观察者都将消耗相同的值序列。
- 一个热点观察者发出的价值与其订阅无关,即观察者收到的价值是订阅时间的函数。
然而,我觉得热与寒冷仍然是一个混乱的来源。 所以这是我的问题:
-
所有rx观察者在默认情况下都是冷的(除了科目)?
我经常看到事件是热门的可观察事物的尖端隐喻,但是我也读到
Rx.fromEvent(input, 'click')
是一个冷的可观察的Rx.fromEvent(input, 'click')
(?)。 -
有哪些Rx运营商将冷观测变成热门观测(除了
publish
和share
)?比如说,它是如何与Rx运算符
withLatestFrom
? 让cold$
是一个冷的可观察的,在某个地方被订阅。 将sth$.withLatestFrom(cold$,...)
是一个热点?或者如果我做
sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)
并订阅sth1
和sth2
,我会一直看到这两个相同的值吗? -
我认为
Rx.fromEvent
创造了冷的可观察性,但事实并非如此,正如答案中提到的那样。 但是,我仍然对这种行为感到困惑: codepen.io/anon/pen/NqQMJR?editors=101 。 不同的订阅从相同的观察值获得不同的值。 是不是共享click
事件?
几个月后,我回到原来的问题,并希望分享所获得的知识。 我将使用下面的代码作为解释支持( 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(){});
正如其中一个答案所述,定义一个observable可以导致一系列的回调和参数注册。 数据流必须被踢入,这是通过subscribe
功能完成的。 A(简化图示)详细流程可以在此后找到。
观察对象默认情况下是冷的。 订阅观察将导致上游订阅链发生。 最后的订阅导致执行一个函数,该函数将处理一个数据源并将其数据发送给其观察者。
那个观察者又转向下一个观察者,导致下游的数据流向下沉观察者。 下面的简单说明显示了当两个订阅者订阅相同的可观察事件时的订阅和数据流。
热可观测量可以通过使用一个主题或通过multicast
操作符(及其衍生词,参见下面的注3)来创建。
引擎盖下的multicast
运算符利用主题并返回可连接的可观察对象。 所有对运营商的订阅都将订阅内部主题。 当connect
被调用时,内部主体订阅上游observable,数据流向下游。 主题在内部操纵订阅的观察者列表,并将传入的数据组播到所有订阅的观察者。
下图总结了这种情况。
最后,理解由观察者模式引起的数据流动和运营商的实现更重要。
例如,如果obs
很热,是hotOrCold = obs.op1
冷还是热? 不管答案是什么,
- 如果没有
obs.op1
用户,obs.op1
会有数据流经op1
。 如果有热门的用户,那就意味着obs.op1
可能会丢失一些数据 - 假设
op1
不是类似多播的运算符,订阅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
更新 :另见以下文章,在这里 ,那里 )由本莱斯在这个问题上。
关于主题的更多细节可以在其他SO问题中找到: 不同RxJS主题的语义是什么?
你的总结,和相关的问题都是正确的,我认为这个术语可能会让你感到困惑。 我建议你把冷热可观测量看成主动和被动观测量(分别)。
也就是说,一个活跃(热门)的可观察者将会散发项目,无论是否有人订阅。 典型的例子,再次,按钮点击事件发生是否有人正在倾听他们。 这个区别是重要的,因为,例如,如果我点击一个按钮,然后订阅按钮点击(按顺序),我将不会看到已经发生的按钮点击。
被动(冷)观察将等待,直到用户存在之前,放射物品。 设想一个按钮,你不能点击它,直到有人正在听事件 – 这将确保你总是看到每一个点击事件。
所有的Rx观测值都是默认的“冷”(或被动)? 不, Rx.fromEvent(input, 'click')
例如是热的(或主动的)可观察的。
我还读到
Rx.fromEvent(input, 'click')
是一个冷观察(?)
事实并非如此。
是否有Rx操作员将感冒变成可观察的热点?
将热(主动)观察变成冷(被动)观察的概念是这样的:你需要记录没有订阅时发生的事件,并将这些项目(以各种方式)提供给将来出现的订户。 一种方法是使用主题 。 例如,您可以使用ReplaySubject
来缓冲所播放的项目,并将其重播给未来的订阅者。
您命名的两个操作员( publish
和share
)都在内部使用主题来提供该功能。
它是如何与Rx运算符
withLatestFrom
? 让cold$
是一个已经订阅的冷观察。 请问something$.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 。 不同的订阅从相同的观察值获得不同的值。 是不是共享click
事件?
我会通过Enigmativity向你指出一个关于同样行为的问题。 这个答案会比我更好地解释它,但是它的要点是源(click事件)是“共享的”,是的,但是你的操作不是。 如果你想分享不只是点击事件,但也要分享它的操作,你需要明确这样做。
你的codepen中的values
是懒惰的 – 没有任何事情发生,直到某些订阅,在这一点上,它贯穿并连接起来。 所以在你的例子中,虽然你正在订阅同一个变量,但它正在创建两个不同的流; 每个订阅呼叫一个。
您可以将values
视为是附加了该map
click
流的生成器。
。该地图末尾的.share()
会创建我们期望的行为,因为它是隐式订阅的。
这不是所有问题的答案(我想知道所有这些问题!)但是肯定的是,所有fromEvent
观察点都很热。 点击似乎不是因为它不是像“mousemove”这样的“连续”事件,而是在创建Observable时,无论如何订阅源代码( addEventListener
或者调用)都只执行一次。 所以很热 你可以在操作符的源代码中看到它 – 无论事件名称或来源是什么,创建的observable都是share
。