冷热观察:有"热"和"冷"运营商吗?

use*_*222 60 javascript reactive-programming rxjs rxjs5 angular

我回顾了以下SO问题: 什么是热和冷可观测量?

总结一下:

  • 当一个cold observable有一个观察者使用它时,它会发出它的值,即观察者接收的值序列与订阅时间无关.所有观察者都将使用相同的值序列.
  • 热的observable独立于其订阅发出值,即观察者接收的值是订阅时间的函数.

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

  • 默认情况下所有rx可观察量是否都是冷的(主题除外)?

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

  • 是否有什么/哪些Rx运算符将冷观测值转换为热观测值(除了publish和之外share)?

    例如,它如何与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事件不是共享的吗?

use*_*222 73

几个月后,我回到原来的问题,并希望在此期间分享所获得的知识.我将使用以下代码作为解释支持(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(){});
Run Code Online (Sandbox Code Playgroud)

如其中一个答案所述,定义一个observable会导致一系列回调和参数注册.必须启动数据流,这是通过该subscribe功能完成的.之后可以找到(简化说明)详细流程.

简化的流程图

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

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

冷可观察的简化流程图

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

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

下图总结了这种情况.

热可观察的简化流程图

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

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

  • 如果没有订户obs.op1,则不会有数据流过op1.如果有热门用户obs,这意味着obs.op1可能会丢失数据
  • 假设这op1不是类似多播的运算符,订阅两次hotOrCold将订阅两次op1,并且每个值obs将流过两次op1.

备注:

  1. 此信息应对Rxjs v4有效.虽然版本5经历了相当大的变化,但大部分仍然是逐字适用的.
  2. 未表示取消订阅,错误和完成流程,因为它们不在问题范围内.调度程序也不会被考虑在内.除其他外,它们影响数据流的时间,但先验不是它的方向和内容.
  3. 根据用于多播的主题类型,有不同的派生多播运算符:

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关于该主题的以下文章,此处和那里.

关于主题的更多细节可以在另一个SO问题中找到:不同RxJS科目的语义是什么?

  • 正确记录主题仍然是好的(目前的文档很难弄清楚).我认为最好的方法是如果你在这个主题上记录一个特定的问题(没有双关语意).在那里回答这个问题将超出范围,它将允许添加更多细节.目前的答案已经很长了,我想让它专注于这个问题.问题可能是"各种Rxjs主题的语义是什么"或者你用什么方式简明地形成它. (2认同)

Why*_*rrh 8

您的摘要和链接的问题都是正确的,我认为术语可能让您感到困惑.我建议你将冷热可观测量视为主动和被动可观测量(分别).

也就是说,无论某人是否订阅,活动(热)可观察者都将发出项目.再一次,按钮点击事件发生在规范的例子中,无论是否有人在听他们.这种区别很重要,因为,例如,如果我单击一个按钮然后订阅按钮单击(按此顺序),我将看不到已经发生的按钮单击.

被动(冷)可观察者将在发射物品之前等待用户存在.想象一个按钮,在有人正在收听事件之前你无法点击它,这将确保你总能看到每一个点击事件.

默认情况下,所有Rx可观测量都是"冷"(或被动)吗?不,Rx.fromEvent(input, 'click')例如,热(或活跃)可观察.

我还读到这Rx.fromEvent(input, 'click')是一个冷的观察(?)

事实并非如此.

是否有Rx操作符将冷观察变为热观察?

将热(活动)可观察对象变为冷(被动)可观察对象的概念是:您需要记录在没有订阅的情况下发生的事件,并将这些项目(以各种方式)提供给将来出现的订阅者.一种方法是使用主题.例如,您可以使用a ReplaySubject来缓冲发出的项目并将它们重播给将来的订阅者.

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

它如何与Rx运算符一起使用withLatestFrom?让我们cold$成为一个冷酷的观察者.会something$.withLatestFrom(cold$,...)是一个热门观察?

如果something是热的可观察的,那么是的.如果something是冷观察,那么没有.回到事件示例,if something是一个按钮点击事件流:

var clickWith3 = Rx.fromEvent(input, 'click')
    .withLatest(Rx.Observable.from([1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)

或者,如果我不foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...)和订阅foobar,我总会看到两个相同的值?

不总是.同样,如果foobar是不同的按钮点击,例如,那么你会看到不同的值.同样,即使它们是相同的按钮,如果你的组合函数(第二个参数withLatest)没有为相同的输入返回相同的结果,那么你将看不到相同的值(因为它将被调用两次,如解释下面).

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

我将通过Enigmativity向你指出这个关于同样行为的问题的答案.这个答案会比我更好地解释它,但它的要点是源(点击事件)是"共享的",是的,但你对它的操作不是.如果您不仅要共享click事件,还要共享其上的操作,则需要明确地共享.