如何避免Rx中的毛刺 [英] how to avoid glitches in Rx

查看:115
本文介绍了如何避免Rx中的毛刺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与其他FRP库不同,Rx不会阻止毛刺:使用时间不匹配的数据调用回调。有没有一种解决这个问题的好方法?



作为一个例子,假设我们有一系列昂贵的计算来自单个流(例如,而不是_.identity ,下面,我们做一个排序,或者ajax fetch)。我们做了distinctUntilChanged以避免重新计算昂贵的东西。

  sub = new Rx.Subject(); 
a = sub.distinctUntilChanged()。share();
b = a.select(_。identity).distinctUntilChanged()。share();
c = b.select(_。identity).distinctUntilChanged();
d = Rx.Observable.combineLatest(a,b,c,function(){return _.toArray(arguments);});
d.subscribe(console.log.bind(console));
sub.onNext('a');
sub.onNext('b');

第二个事件最终会导致一些错误的状态:我们得到三个事件,而不是一,浪费了一堆cpu,并要求我们明确解决不匹配的数据。



这个特殊的例子可以通过删除distinctUntilChanged来解决,并写一些不知道的如果输入未更改,scan()函数将传递先前的结果。然后你可以压缩结果,而不是使用combineLatest。它很笨拙但可行。



但是如果在任何地方都存在异步,例如ajax调用,然后zip不起作用:ajax调用将同步(如果缓存)或异步完成,因此你不能使用zip。



编辑



尝试用一个更简单的例子来澄清所需的行为:



你有两个溪流,a和b。 b取决于a。 b是异步的,但是浏览器可以缓存它,因此它可以独立地更新,也可以同时更新。因此,浏览器中的特定事件可能会导致以下三种情况之一:更新; b更新; a和b都更新。所需的行为是在所有三种情况下都要调用一次回调(例如渲染方法)。



zip不起作用,因为当a或b单独触发时,我们从zip获得回调。 combineLatest不起作用,因为当a和b一起发射时,我们得到两个回调。

解决方案

概念


a和b更新


其中 a b 是可观察的,在Rx中不作为基元存在。



没有无损的一般运算符可以定义,以决定何时从 a 接收通知是否应该将其传递到下游或延迟直到它收到来自 b 。 Rx中的通知本身并不带有两个语义或Rx语法之外的任何语义。



此外,Rx的串行合同阻止运营商利用重叠通知以实现此目标。 (虽然我怀疑依赖竞争条件不是你想要的方法。)



参见 Rx设计指南



因此,我的意思是没有可以定义的无损,一般运算符......给定两个可观察量 a b 独立通知,任何试图决定何时从 a b 收到通知的运营商是否必须立即推送或等待其他值,必须依赖于任意时间。这是猜测。所以这个假设的运算符必须删除值(例如, DistinctUntilChanged Throttle ),或者删除时间(例如, Zip 缓冲区),但可能是两者的某种组合。



因此,如果代理能够单独推送 a ,或单独推送 b ,或 a b 一起作为通知单位,然后开发人员有责任将通知单元本身的概念重新实现。



需要3种状态:a | b | {a,b}



(请原谅我糟糕的JS)

  var ab = function(a,b){this.a = a; this.b = b; } 
sub.onNext(new ab('a')); //单独处理
sub.onNext(new ab('a','b')); //将a和b一起处理
sub.onNext(new ab(null,'c')); //单独处理c

observable查询的形状不再重要。必须定义观察者以接受此数据类型。生成器有责任根据其内部状态的语义应用任何必要的缓冲或计时计算,以便为其观察者生成正确的通知。



<顺便说一句,谢谢你在编辑中提供了一个简单的解释(无论如何我似乎都很清楚)。我第一次听说此Rx论坛讨论。如你所见,它从未真正结束。现在我想知道OP的问题是否真的如此简单,假设我当然正确地理解了你的问题。 : - )



更新:



这是另一个相关的讨论,包括更多关于为什么Rx不是FRP的想法:



https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71- c97b-428e-ad71-324055a3cd03 / another-discussion-on-glitches-and-rx?forum = rx


Unlike other "FRP" libraries, Rx doesn't prevent glitches: callbacks invoked with time-mismatched data. Is there a good way to work around this?

As an example, imagine that we have a series of expensive computations derived from a single stream (e.g. instead of _.identity, below, we do a sort, or an ajax fetch). We do distinctUntilChanged to avoid recomputing the expensive things.

sub = new Rx.Subject();
a = sub.distinctUntilChanged().share();
b = a.select(_.identity).distinctUntilChanged().share();
c = b.select(_.identity).distinctUntilChanged();
d = Rx.Observable.combineLatest(a, b, c, function () { return _.toArray(arguments); });
d.subscribe(console.log.bind(console));
sub.onNext('a');
sub.onNext('b');

The second event will end up causing a number of glitchy states: we get three events out, instead of one, which wastes a bunch of cpu and requires us to explicitly work around the mismatched data.

This particular example can be worked around by dropping the distinctUntilChanged, and writing some wonky scan() functions to pass through the previous result if the input hasn't changed. Then you can zip the results, instead of using combineLatest. It's clumsy, but doable.

However if there is asynchrony anywhere, e.g. an ajax call, then zip doesn't work: the ajax call will complete either synchronously (if cached) or asynchronously, so you can't use zip.

Edit

Trying to clarify the desired behavior with a simpler example:

You have two streams, a and b. b depends on a. b is asynchronous, but the browser may cache it, so it can either update independently of a, or at the same time as a. So, a particular event in the browser can cause one of three things: a updates; b updates; both a and b update. The desired behavior is to have a callback (e.g. render method) invoked exactly once in all three cases.

zip does not work, because when a or b fires alone, we get no callback from zip. combineLatest does not work because when a and b fire together we get two callbacks.

解决方案

The concept

both a and b update

where both a and b are observables, doesn't exist as a primitive in Rx.

There is no lossless, general operator that can be defined to decide when it receives a notification from a whether it should pass it downstream or hold off until it receives a notification from b. Notifications in Rx do not natively carry "both" semantics, or any semantics beyond the Rx Grammar for that matter.

Furthermore, Rx's serial contract prevents an operator from taking advantage of overlapping notifications in an attempt to achieve this goal. (Though I suspect that relying on race conditions isn't your desired approach anyway.)

See §§4.2, 6.7 in the Rx Design Guidelines.

Thus, what I meant above by "There is no lossless, general operator that can be defined..." is that given two observables a and b with independent notifications, any operator that attempts to decide when it receives a notification from a or b whether it must push immediately or wait for the "other" value, must rely on arbitrary timings. It's guesswork. So this hypothetical operator must either drop values (e.g., DistinctUntilChanged or Throttle), or drop time (e.g., Zip or Buffer), though probably some combination of both.

Therefore, if the agent has the ability to push a alone, or b alone, or a and b together as a notification unit, then it's the developer's responsibility to reify this concept of notification unit themselves.

A 3-state type is required: a | b | {a,b}

(Please excuse my lousy JS)

var ab = function(a, b) { this.a = a; this.b = b; }
sub.onNext(new ab('a'));        // process a alone
sub.onNext(new ab('a', 'b'));   // process a and b together
sub.onNext(new ab(null, 'c'));  // process c alone

The shape of the observable's query no longer matters. Observers must be defined to accept this data type. It's the generator's responsibility to apply any necessary buffering or timing calculations based on the semantics of its internal state in order to produce correct notifications for its observers.

By the way, thank you for providing a simple explanation in your edit (it seems clear to me anyway). I had first heard about "glitches" in this Rx forum discussion. As you can see, it was never really concluded. Now I wonder whether that OP's problem was really as simple as this, assuming that I've understood your problem correctly, of course. :-)

Update:

Here's another related discussion, including some more of my thoughts on why Rx is not FRP:

https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71-c97b-428e-ad71-324055a3cd03/another-discussion-on-glitches-and-rx?forum=rx

这篇关于如何避免Rx中的毛刺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆