冷热观察:热点和热点是否存在?和'冷''运营商?

时间:2015-08-24 19:42:45

标签: javascript angular rxjs reactive-programming rxjs5

我回顾了以下SO问题: What are the Hot and Cold observables?

总结:

  • cold observable在有观察者使用它时发出其值,即观察者接收的值序列与订阅时间无关。所有观察者都将使用相同的值序列。
  • hot observable独立于其订阅发出值,即观察者收到的值是订阅时间的函数。

然而,我觉得热和冷仍然是混乱的根源。所以这是我的问题:

  • 默认情况下所有rx observable都是冷的(主题除外)?

    我经常读到事件是热观察的典型隐喻,但我也读到Rx.fromEvent(input, 'click')是冷可观察的(?)。

  • 是否有/哪些Rx运算符将冷可观察量转换为热可观察量(publishshare除外)?

    例如,它如何与Rx运算符withLatestFrom一起使用?让cold$成为一个冷的可观察者,它已被某个地方订阅。 sth$.withLatestFrom(cold$,...)会成为热门观察者吗?

    或者如果我sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...)并订阅sth1sth2,我是否会始终看到sth的相同值?

  • 我认为Rx.fromEvent会产生冷可观察性,但事实并非如此,正如其中一个答案所述。但是,我仍然对这种行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个observable获得不同的值。我没有分享click个活动吗?

3 个答案:

答案 0 :(得分:71)

几个月后,我回到原来的问题,并希望在此期间分享所获得的知识。 我将使用以下代码作为解释支持(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函数完成的。 此后可以找到(简化说明)详细流程。

Simplified flow diagram

默认情况下,Observable很冷。订阅可观察量将导致上游订阅链发生。最后一个订阅导致执行一个函数,该函数将处理一个源并将其数据发送给它的观察者。

观察者轮流向下一个观察者发射,导致下游数据流向下到观察者。以下简化图示显示了当两个订阅者订阅相同的observable时的订阅和数据流。

Cold observable simplified flow diagram

可以通过使用主题或通过multicast运算符(及其衍生词,参见下面的注释3)创建热观察值。

引擎盖下的multicast运算符使用主题并返回可连接的observable。对运营商的所有订阅都将是对内部主题的订阅。当调用connect时,内部主体订阅上游可观察者,数据流向下游。 主体在内部操纵订阅的观察者列表并将传入的数据多播到所有订阅的观察者。

下图总结了这种情况。

Hot observable simplified flow diagram

最后,理解由观察者模式和运营商实施引起的数据流更为重要。

例如,如果obs很热,hotOrCold = obs.op1是冷还是热?无论答案是什么:

  • 如果obs.op1没有订阅者,则数据不会流经op1。如果有热门用户obs,则表示obs.op1可能会丢失数据
  • 假设op1不是类似多播的运算符,则向hotOrCold订阅两次将向op1订阅两次,而来自obs的每个值将在op1中流过两次{ {1}}。

注意:

  1. 此信息应对Rxjs v4有效。虽然版本5已经消失了 通过相当大的变化,大部分仍然是逐字适用。
  2. 未表示取消订阅,错误和完成流程,如 他们不在问题的范围内。调度程序也不是 考虑到了。除此之外,它们影响了时间 数据流,但先验不是它的方向和内容。
  3. 根据用于多播的主题的类型,有 不同的派生组播运营商:
  4. 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

    Ben Lesh关于该主题的

    更新:另请参阅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缓冲发出的项目并将其重播给未来的订阅者。

您命名的两个运算符(publishshare)都在内部使用主题来提供该功能。

  

它如何与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$,...)并订阅foobar,我是否会始终看到相同的值?

并非总是如此。同样,如果foobar是不同按钮上的点击,那么您会看到不同的值。同样,即使它们是相同的按钮,如果你的组合函数(withLatest的第二个参数)没有为相同的输入返回相同的结果,那么你将看不到相同的值(因为它将是叫了两次,如下所述。

  

我认为Rx.fromEvent创造了冷可观察性,但事实并非如此,正如其中一个答案所述。但是,我仍然对这种行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101。不同的订阅从同一个observable获得不同的值。我没有分享click个活动吗?

我会指出this great answer by Enigmativity我对同一行为的问题。这个答案会比我能解释得更好,但它的要点是源(点击事件)是&#34;共享&#34;,是的,但你对它的操作不是。如果您不仅要共享click事件,还要共享其上的操作,则需要明确地共享。

答案 2 :(得分:4)

你的codepen中的

values是懒惰的 - 在订阅之前没有任何事情发生,此时它会贯穿并连接起来。所以在你的例子中,虽然你订阅了同一个变量,但它创建了两个不同的流;每个订阅电话一个。

您可以将values视为click附加map的流的生成器。

该映射末尾的

.share()将创建我们期望的行为,因为它隐式订阅。