XStreams中忽略的第二个合并分支

时间:2019-06-09 09:30:56

标签: reactive-programming cyclejs xstream-js

我正在使用storagestate插件开发Cycle JS应用。

该应用使用xstream作为反应库。

我陷入了一种奇怪的行为。

我的信息流就是这个图

enter image description here

在第一次会话var更新中,我得到了以下调试结果:

  • 调试0
  • 调试1
  • 调试3

问题:未执行“调试2”分支

如果我更新会话项(以便产生一个新的存储事件),则两个分支都按预期执行

  • 调试0
  • 调试1
  • 调试2
  • 调试3

如果在“调试0”处添加.remember(),也会发生相同的良好行为。 enter image description here

  • 调试0
  • 调试1
  • 调试2
  • 调试3

即使是陌生人,如果删除过滤器,流程也会按预期工作 enter image description here

没有过滤器(并且不记得),流程从第一个事件开始就给出该结果

  • 调试0
  • 调试1
  • 调试2
  • 调试3

我的怀疑是在附加第二个分支之前,在“调试0”处观察到某种情况,因此第一个事件已被使用。 但是,如果两个分支xs.merged在一起怎么办?如何执行一个分支而不执行第二个分支?这两个分支没有过滤器或其他处理,它们合并映射到化简函数。 关于如何调试和解决这种情况有什么建议吗?

1 个答案:

答案 0 :(得分:5)

之所以会发生此问题,是因为storage.session.getItem在订阅后立即发出 ,并且merge(a$, b$)在订阅a$之前就订阅了b$,因此a$收到事件,但是到b$订阅时,它已经来不及了。这个问题是众所周知的,并称为毛刺(在反应式编程中),通常在存在菱形流图时发生,这正是您的情况。

我有两篇有关故障的博客文章,它们可以为您提供更多的背景信息:Primer on RxJS schedulersRx glitches aren't actually a problem。它提到了RxJS,但是xstream在实现方面与RxJS非常接近。 xstream和RxJS之间的区别在于,xstream流始终是多播(“共享”)的,并且RxJS具有许多调度程序类型,但是xstream只有一种。 RxJS中的默认调度程序与xstream具有相同的行为。

解决方案是在到达菱形之前应用.remember()。这是因为所发出的值需要为该流的其他使用者缓存。 .remember()只需将流转换为MemoryStream。我认为源流最初是一个MemoryStream,并且映射一个MemoryStream会创建其他MemoryStreams,但是filter是一个破坏了它的运算符。 filter始终返回一个Stream,其原因是MemoryStreams应该始终具有当前值,但是filter可以删除值,因此过滤后的流可能会没有具有任何当前值。

作为Cycle.js的作者,我认为cyclejs / storage的设计方法不是最好的,我认为我们将找到设计这些API的方法,以最大程度地减少与MemoryStream和Stream的混淆。但是暂时,重要的是要了解这两者之间的区别并计划应用程序,从而避免出现菱形(和小故障),或者在正确的位置使用.remember()