首页 文章

热和冷可观测量:是否有'hot'和'cold'运算符?

提问于
浏览
51

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

总结一下:

  • cold observable在有观察者使用它时发出其值,即观察者接收的值序列与订阅时间无关 . 所有观察者都将使用相同的值序列 .

  • hot observable独立于其订阅发出值,即观察者接收的值是订阅时间的函数 .

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

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

我经常读到事件是热观察的典型隐喻,但我也读到 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 事件?

4 回答

  • 8

    这不是你所有问题的答案(我想知道所有问题!)但是当然,所有 fromEvent Observable都很热门 . 点击似乎不是因为它不像mousemove那样"continous"事件,但是当创建Observable时,无论如何订阅源( addEventListeneron 调用)只进行一次 . 所以很热 . 您可以在运算符herethere的源代码中看到它 - 无论事件名称或来源是什么,创建的observable都是 share d .

  • 3

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

    您可以将 values 视为 click 的流生成器,并附加了 map .

    在该映射的末尾 .share() 将创建我们期望的行为,因为它是隐式订阅的 .

  • 4

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

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

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

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

    我还读到Rx.fromEvent(输入,'click')是一个冷可观察(?)

    事实并非如此 .

    是否存在可将冷观察变为热观测值的Rx算子?

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

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

    如何使用Rx运算符withLatestFrom?让冷美元成为一个已被认可的冷可观察者 . $ .withLatestFrom(冷$,......)会成为热门观察者吗?

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

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

    或者,如果我foo $ .withLatestFrom(冷$,...),bar $ .withLatestFrom(冷$,...)并订阅foo和bar,我是否总能看到两者的值相同?

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

    我认为Rx.fromEvent会创建冷可观察对象,但事实并非如此,正如其中一个答案所述 . 但是,我仍然对此行为感到困惑:codepen.io/anon/pen/NqQMJR?editors=101 . 不同的订阅从同一个observable获得不同的值 . 是不是分享了点击事件?

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

  • 68

    几个月后,我回到原来的问题,并希望在此期间分享所获得的知识 . 我将使用以下代码作为解释支持(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 时,内部主题订阅上游observable,数据流向下游 . 主体在内部操纵订阅的观察者列表并将传入的数据多播到所有订阅的观察者 .

    下图总结了这种情况 .

    Hot observable simplified flow diagram

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

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

    • 如果 obs.op1 没有订户,则没有数据流过 op1 . 如果订阅者热到 obs ,则表示 obs.op1 可能会丢失数据

    • 假设 op1 不是类似多播的运算符,订阅两次 hotOrCold 将订阅两次 op1obs 的每个值将通过 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?

相关问题