Observables(Rx.js)与ES2015生成器相比如何?

时间:2016-12-27 16:52:11

标签: javascript ecmascript-6 generator reactive-programming rxjs5

据我了解,以下是解决异步编程工作流的技术:

  1. 回调(CSP)
  2. 承诺
  3. 更新的方法:

    1. Rx.js Observables(或mostjs,bacon.js,xstream等)
    2. ES6发电机
    3. 异步/等待
    4. 我们现在正在远离回调&对这些新方法的承诺。我目前理解的是 - Async / Await更像是在ES2015生成器之上更清晰的抽象。

      我无法理解的是Observables和Generators之间的概念差异。我已广泛使用它们并且没有使用它们。

      令我困惑的是Observables和Generators的用例。我得出的结论是,他们最终解决了同样的问题 - 异步性。只有我看到的潜在差异是生成器固有地为代码提供命令式语义,而使用Rxjs的Observable似乎提供了反应范式。但就是这样吗?

      这应该是Observable和Generator之间选择的标准吗?有什么优点和缺点。

      我错过了大局吗?

      同样Observable最终制作成未来的Ecmascript,Promises(带有可取消令牌)/ Observable / Generators会相互竞争吗?

3 个答案:

答案 0 :(得分:14)

Observable推动变化,因此可观察的,而不是对其作出反应的功能是可控制的。另一方面,生成器要求您从中提取值。因此,对新值作出反应的函数决定何时为新值做好准备。

我在使用observables时遇到了背压问题,但是对于生成器,你可以根据需要放慢速度。

编辑:最后一个问题。承诺只是只发出一次的可观察物,所以我认为它们不会相互竞争。我认为真正的战斗将是async / await vs observables,async / await有一个良好的开端,并且已经在C#(现在是Node.js)。但是可观察到的是那种甜美的FRP感觉,而且功能性编程非常酷,所以我认为他们最终都会有很大的思想共享。

Edit2:AndréStaltz,Cycle.js和xstream的作者,以及Rx.js的撰稿人,写了一篇关于生成器和Observable如何关联的伟大的文章(2018-01-31)。特别是,他展示了他们如何从一个共同的基类继承。

  

现在消费者可以是一个倾听者(“观察者”)或者一个拉动者,它取决于消费者是否会拉动生产者。生产者可以是可听的(“可观察的”)或Pullable(“可迭代的”),无论是主动发送数据还是仅按需发送数据,都取决于生产者。如您所见,消费者和生产者都是相同类型的简单功能:

     

(num,payload)=>空隙

     

因此,我们构建的任何运算符都可以用于反应式编程或可迭代编程,只是因为这两种模式之间的界限变得模糊,而且它不再是可观察对象与迭代对象,它只是关于生产者和消费者之间数据的转换。 / p>

我建议您阅读[link]。本文介绍了“Callbags”,这是一个用于反应式和可迭代编程的回调规范。他实现了该规范,以便为可迭代和反应式编程提供a tiny library。为了吸引您阅读文章并查看库,以下是基于他介绍的规范的7kb库中的一些示例:

反应式编程示例

从每秒钟滴答的时钟中挑选前5个奇数,然后开始观察它们:

const {forEach, interval, map, filter, take, pipe} = require('callbag-basics');

pipe(
  interval(1000),
  map(x => x + 1),
  filter(x => x % 2),
  take(5),
  forEach(x => console.log(x))
);

// 1
// 3
// 5
// 7
// 9

可重复编程示例

从一系列数字中挑选其中的5个并将它们除以4,然后开始逐个拉出这些数字:

const {forEach, fromIter, take, map, pipe} = require('callbag-basics');

function* range(from, to) {
  let i = from;
  while (i <= to) {
    yield i;
    i++;
  }
}

pipe(
  fromIter(range(40, 99)), // 40, 41, 42, 43, 44, 45, 46, ...
  take(5), // 40, 41, 42, 43, 44
  map(x => x / 4), // 10, 10.25, 10.5, 10.75, 11
  forEach(x => console.log(x))
);

// 10
// 10.25
// 10.5
// 10.75
// 11

答案 1 :(得分:1)

我知道这个问题是在 2016 年发布的,其中 generator 仍然同步使用。

不过,我认为今天一个更有趣(合适)的问题是 async generatorreactive observablereactive programming 之间的区别。请允许我离题。

在下文中,我将使用:

  • A 代表 async/await, promise
  • B 代表 async generator
  • C 代表 reactive observable

首先,它们都旨在处理 async 数据。重要的是细节。

如果我们有一个有限且小的 async 数据源,例如单个 HTTP 请求,磁盘上只有几 KB 的数据。然后 A 获胜,简单明了。

当数据源变得无限(例如用户点击)或太大而无法保存在内存中时,A 将无法正常工作,因为我们很快就会遇到意外的复杂性(首先要处理背压) . BC 总体上都很出色,因为它们都以一种或另一种方式提供背压设施。

然后,当数据源开始需要缓冲、去重、去抖动、与其他数据源合并/交​​错等时,C 获胜,因为许多库将提供通用运算符来帮助处理常见的流问题。一个示例用例是阻止用户在短窗口(例如 5 秒)内发送垃圾评论。

这是否意味着C总体上比B好?

在我看来,没有。尽管 C 更通用,但 B 更简单、更灵活,并且与语言的集成更好(例如 for await ... of)。而且它几乎不需要您按照 C 的要求更改整个编程范式。

答案 2 :(得分:0)

您可以将rxjs observable视为异步生成器,即生成promises的生成器。仅仅因为在我们调用.next(与常规生成器相反)时,内容不能保证准备就绪

  • 订阅者将永久消耗生成器内容(调用.next)
  • 的无限循环
  • 等待已退回的承诺被解决(或撤销)以执行您想要的操作
  • observable(由异步生成器制作)将在生成器返回时完成。

More reading

asynchronous Iterators proposal