我回顾了以下SO问题:What are the Hot and Cold observables?
总结一下:
-
cold observable在有观察者使用它时发出其值,即观察者接收的值序列与订阅时间无关 . 所有观察者都将使用相同的值序列 .
-
hot observable独立于其订阅发出值,即观察者接收的值是订阅时间的函数 .
然而,我觉得热和冷仍然是混乱的根源 . 所以这是我的问题:
- 默认情况下所有rx可观察物是否都是冷的(主题除外)?
我经常读到事件是热观察的典型隐喻,但我也读到 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
事件?
4 回答
这不是你所有问题的答案(我想知道所有问题!)但是当然,所有
fromEvent
Observable都很热门 . 点击似乎不是因为它不像mousemove那样"continous"事件,但是当创建Observable时,无论如何订阅源(addEventListener
或on
调用)只进行一次 . 所以很热 . 您可以在运算符here和there的源代码中看到它 - 无论事件名称或来源是什么,创建的observable都是share
d .你的codepen中的
values
是懒惰的 - 在订阅之前没有任何反应,此时它会贯穿并连接起来 . 所以在你的例子中,虽然你订阅了同一个变量,但它创建了两个不同的流;每个订阅电话一个 .您可以将
values
视为click
的流生成器,并附加了map
.在该映射的末尾
.share()
将创建我们期望的行为,因为它是隐式订阅的 .您的摘要和关联的问题都是正确的,我认为这个术语可能让您感到困惑 . 我建议你将冷热可观测量视为主动和被动可观测量(分别) .
也就是说,活跃(热)可观察者将发出物品,无论是否有人订阅 . 再一次,按钮点击事件发生在规范的例子中,无论是否有人在听他们 . 这种区别很重要,因为,例如,如果我单击一个按钮然后订阅按钮单击(按此顺序),我将看不到已经发生的按钮单击 .
被动(冷)可观察者将在发射物品之前等待用户存在 . 想象一个按钮,在有人正在收听事件之前你无法点击它 - 这将确保你总能看到每一个点击事件 .
默认情况下,所有Rx都可观察到"cold"(或被动)吗?不,
Rx.fromEvent(input, 'click')
例如是热(或活跃)可观察的 .事实并非如此 .
将热(活动)可观察对象转换为冷(被动)可观察对象的概念是:您需要记录在没有订阅的情况下发生的事件,并将这些项目(以各种方式)提供给将来出现的订阅者 . 一种方法是使用Subject . 例如,您可以使用
ReplaySubject
缓冲发出的项目并将其重播给将来的订阅者 .您命名的两个运算符(
publish
和share
)都在内部使用主题来提供该功能 .如果
something
是一个热门的观察者,那么是的 . 如果something
是冷可观察的,那么没有 . 返回事件示例,如果something
是按钮单击事件流:不总是 . 同样,如果例如
foo
和bar
点击了不同的按钮,那么您会看到不同的值 . 同样,即使它们是相同的按钮,如果你的组合函数(withLatest
的第二个参数)没有为相同的输入返回相同的结果,那么你不会看到相同的值(因为它将被调用两次,如下所述) .我会指出你对我有同样行为的问题this great answer by Enigmativity . 这个答案会比我能解释得更好,但它的要点是源(点击事件)是"shared",是的,但是你对它的操作不是 . 如果您不仅要共享click事件,还要共享其上的操作,则需要明确地共享 .
几个月后,我回到原来的问题,并希望在此期间分享所获得的知识 . 我将使用以下代码作为解释支持(jsfiddle):
如其中一个答案所述,定义一个observable会导致一系列回调和参数注册 . 必须启动数据流,这是通过
subscribe
函数完成的 . 之后可以找到(简化的说明)详细流程 .Observable默认是冷的 . 订阅可观察量将导致上游订阅链发生 . 最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者 .
该观察者反过来向下一个观察者发射,导致下游数据流向下到观察者 . 以下简化图示显示了当两个订阅者订阅相同的observable时的订阅和数据流 .
热观察可以通过使用主题或通过
multicast
运算符(及其衍生物,参见下面的注释3)来创建 .引擎盖下的
multicast
运算符使用主题并返回可连接的observable . 对运营商的所有订阅都将是对内部主题的订阅 . 当调用connect
时,内部主题订阅上游observable,数据流向下游 . 主体在内部操纵订阅的观察者列表并将传入的数据多播到所有订阅的观察者 .下图总结了这种情况 .
最后,理解由观察者模式和运营商实施引起的数据流更为重要 .
例如,如果
obs
很热,是hotOrCold = obs.op1
冷还是热?无论答案是什么:如果
obs.op1
没有订户,则没有数据流过op1
. 如果订阅者热到obs
,则表示obs.op1
可能会丢失数据假设
op1
不是类似多播的运算符,订阅两次hotOrCold
将订阅两次op1
,obs
的每个值将通过op1
流两次 .备注:
此信息应对Rxjs v4有效 . 虽然版本5经历了相当大的变化,但其中大部分仍然是逐字适用的 .
未表示取消订阅,错误和完成流程,因为它们不在问题范围内 . 调度程序也不会被考虑在内 . 除其他外,它们影响数据流的时间,但先验不是它的方向和内容 .
根据用于多播的主题类型,有不同的派生多播运算符:
Subject type |
PublishOperator |
Shareoperator ------------------ | --------------------------- | ----------------- 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 :另见the following articles, here , and there)关于Ben Lesh的话题 .
有关主题的更多详细信息可以在其他SO问题中找到:What are the semantics of different RxJS subjects?