简体   繁体   English

Rx.js fromEvent + flatMapLatest坏了吗?

[英]Rx.js fromEvent + flatMapLatest broken?

Well, the problem itself is kind of hard to describe briefly, so here's a live example to demonstrate. 嗯,问题本身很难简单地描述,所以这里有一个生动的例子来演示。 It seems like I'm misunderstanding something about how Rx.js works, otherwise the functionality here comes from a bug. 似乎我对Rx.js的工作方式有误解,否则这里的功能来自一个错误。

What I tried to do was a simple reactive rendering setup, where what you see on the screen, and what events happen are both described in terms of Observables. 我试图做的是一个简单的反应式渲染设置,您在屏幕上看到的内容以及发生的事件均以Observables来描述。 The problem is that, for some indiscernible reason, the events are dropped entirely when the code is written one way, yet work fine with code that should theoretically be equivalent. 问题在于,由于某种无法理解的原因,以一种方式编写代码时,事件将被完全丢弃,但在理论上应该等效的代码下仍能正常工作。

So, let's start with the first case in the example code above: 因此,让我们从上面的示例代码中的第一种情况开始:

var dom = makeBox('one');
var clicks = Rx.Observable.fromEvent(dom, 'click');

If you create a DOM fragment, then you can simply use fromEvent to get an Observable for whatever event it emits. 如果创建DOM片段,则可以简单地使用fromEvent来获取其发出的任何事件的Observable。 So far, so good. 到现在为止还挺好。 You can click this box and see a bunch of lines written to the log. 您可以单击此框,然后看到写到日志中的许多行。

Now, the next step would be to make the DOM reactive, to express how it changes over time. 现在,下一步将是使DOM具有反应性,以表达其随时间的变化。

var domStream = Rx.Observable.return(makeBox('two'));
var clicks = domStream.flatMapLatest(function(dom) {
  return Rx.Observable.fromEvent(dom, 'click');
});

That would make it an Observable, using return here to produce the simplest, constant case. 这将使其成为可观察的对象,并在此处使用return来产生最简单,恒定的情况。 The events you're interested in would be the ones emitted by the latest version of the dom, and that's exactly what the flatMapLatest operator does. 您感兴趣的事件将是最新版本的dom发出的事件,而这正是flatMapLatest运算符的工作。 This variant still works. 此变体仍然有效。

Ultimately, the goal would be to generate the current DOM state based on some application state. 最终,目标是基于某个应用程序状态生成当前DOM状态。 That is, map it from one Observable to another. 也就是说,将其从一个Observable映射到另一个。 Let's go with the simplest version for now, have a single constant value as the state, and then map it to the same fixed output we used previously: 现在让我们使用最简单的版本,将一个常量值作为状态,然后将其映射到我们之前使用的相同固定输出:

var updates = Rx.Observable.return(1);
var domStream = updates.map(function (update) {
  return makeBox('three');
});
var clicks = domStream.flatMapLatest(function(dom) {
  return Rx.Observable.fromEvent(dom, 'click');
});

This should not be any different from the previous version. 这与以前的版本没有什么不同。 However, this outputs no events, no matter what you do. 但是,无论您做什么,都不会输出任何事件。

What exactly is going on here? 这到底是怎么回事? Did I misunderstand some fundamental concept of Rx, or what? 我是否误解了Rx的一些基本概念,还是什么? I've run into some issues with hot vs cold Observables, but that seems unrelated in this minimal case. 我已经遇到了热的和冷的Observable的一些问题,但是在这种最小的情况下,这似乎无关紧要。 So, I'm kind of out of ideas. 所以,我有点想法不对。 Can anyone enlighten me? 谁能启发我?

Sorry to tell you but it is a Hot vs Cold issue. 不好意思告诉您,但这是一个Hot vs Cold问题。

It is a subtle issue, but the difference between 这是一个微妙的问题,但两者之间的区别

Rx.Observable.return(makeBox('two'))

and

Rx.Observable.return(1).map(function() {return makeBox('three'); })

Is that the first returns a constant every time you subscribe to it, that is, a box that you created initially. 是第一个在您每次订阅它时返回一个常量,即您最初创建的一个框。 The second returns a new box every time the Observable is subscribed to, this causes a problem since you actually subscribe to the domStream variable twice, you are creating two instances of Box three, one which has event handlers but isn't shown and one that does not and is shown. 每次订阅Observable时,第二个都会返回一个框,这会导致问题,因为您实际上两次订阅了domStream变量,正在创建Box 3的两个实例,一个实例具有事件处理程序,但未显示,而另一个没有,并显示。

The fix is that you either need to use approach 2 or you need to convert the third into a hot stream either by using: 解决方法是,你要么需要使用方法2 需要第三转换成热气流或者通过使用:

domStream.replay(1).refCount()

Or by using 或使用

domStream.publish()

then after all subscriptions are completed: 然后在完成所有订阅后:

domStream.connect()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM