use*_*908 7 javascript reactive-programming reactive-extensions-js rxjs
与其他"FRP"库不同,Rx不会阻止毛刺:使用时间不匹配的数据调用回调.有办法解决这个问题吗?
作为一个例子,假设我们有一系列昂贵的计算从单个流派生(例如,而不是_.identity,下面,我们做一个排序,或ajax提取).我们做了明确的改变,以避免重新计算昂贵的东西.
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');
Run Code Online (Sandbox Code Playgroud)
第二个事件最终将导致一些错误的状态:我们得到三个事件,而不是一个,这浪费了一堆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设计指南中的§§4.2,6.7 .
因此,我在上面所说的"没有无损的,可以定义的一般运算符......"是给定两个可观察的a并且b具有独立通知的任何运算符,它们试图决定何时接收通知a或b是否必须推送立即或等待"其他"值,必须依赖任意时间.这是猜测.因此,这个假设的运算符必须丢弃值(例如,DistinctUntilChanged或Throttle),或者丢弃时间(例如,Zip或Buffer),尽管可能是两者的某种组合.
因此,如果代理必须推动能力a独自一人,或b单独,或a与b一起作为一个通知单元,那么这是开发商的责任具体化的概念通知单元本身.
需要三态类型:a | b | {A,B}
(请原谅我糟糕的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
Run Code Online (Sandbox Code Playgroud)
observable查询的形状不再重要.必须定义观察者以接受此数据类型.生成器有责任根据其内部状态的语义应用任何必要的缓冲或计时计算,以便为其观察者生成正确的通知.
顺便说一句,感谢您在编辑中提供简单的解释(无论如何我似乎都很清楚).我在Rx论坛讨论中第一次听说过"故障" .如你所见,它从未真正结束.现在我想知道OP的问题是否真的如此简单,假设我当然正确地理解了你的问题.:-)
更新:
这是另一个相关的讨论,包括我对Rx不是FRP的原因的一些看法:
| 归档时间: |
|
| 查看次数: |
1606 次 |
| 最近记录: |