原文:https://levelup.gitconnected.com/promise-vs-observable-vs-stream-165a310e886f
Promise vs. Observable
Promise
和 Observables
都能够帮助我们在JavaScript 中使用异步功能。Promise
是以异步方式解析值,例如 HTTP 调用。当异步操作完成或失败时,它只处理单个事件。
Observables
就像 Promise
一样,除了它与多个值一起工作,它会自行清理,它可以被取消。如果不再需要HTTP请求或某些异步操作的结果,Observable
的 Subscription 允许取消订阅,而 Promise
最终会回调成功或失败,即使你不再需要通知或它提供的结果。
Observable
类似于 Stream
(在许多语言中), 允许传递0、1 或更多事件,其中为每个事件调用回调。它们处理一系列异步事件。
Observables
除了提供 Promise
中的特性还提供更多特性:
- 随着时间的推移,它可以有多个值:如果我们保持对时事通讯的订阅处于打开状态,我们将获得下一个生成值。发送者决定我们何时接收到它,但我们必须等到它到来。
- 它可以有多个管道
- 它支持聚合操作,如map、filter、forEach、reduce 等等
- 我们可以做一些强大的功能,比如zip、merge或者concat讲不同的 Observable 组合成一个新的
由于 Observables 用于处理“异步事件序列”的响应式编程,让我们看看Uladzimir Sinkevich 的这个真实示例是什么意思:
比如说,今天是星期五,John和他的朋友 Bob 共度这个晚上,吃披萨和看一集《星球大战》。让我们阐述一下他的选择:
- John完成了他的工作。然后去点披萨,并等它做好。然后去接他的朋友,最后(Bob 和 披萨一起)回家看电影。这是一个同步操作,而且时间太长,以至于 John 可能想在那个时候取消这件事。
- John 在网上订了披萨,给 Bob打电话邀请他来家里。他先回到家,披萨也送到了,然后开始看电影(并吃披萨),而无需等待 Bob 出现。这就是异步方法可能发生的情况。
- John 点了披萨,给Bob打电邀请他来家里,回家,然后披萨送到了。但这一次,他等到 Bob 来到,然后才打开电影。这就是响应式方法的意义所在。您等到所有异步操作(更改)完成,然后继续执行进一步操作。
响应式编程是使用异步数据流进行编程。— Andre Staltz
Observable vs. Streams
在这个阶段,在看到我们可以用 Observable 做什么之后,我的同事问了下一个好问题:
“我们能否像在 Java 中处理流一样处理 Observable(在前端),因为它们具有相似的运算符?”
Observable
和 Stream
看起来非常相似,它们有着相似的操作符(filter、map、…),但它们也有显著的不同:
- Stream 只是一个随时间到达的集合
- Observables 就像集合……除了它们随着时间的推移异步到达
- Stream 只能使用一次,而 Observable 可以被订阅多次
- Stream 是基于pull的:数据消费者决定何时从数据生产者那里获得数据;生产者不知道何时将数据传递给消费者;这个仅适用于同步事物,要从集合中拉取值,它必须现在可用!如果我们将同步视为“拉”…,那么我们可以将异步视为“推”…
- Observable 是基于push的:数据生产者(消息通讯的创建者)决定消费者(消息通讯的订阅者)何时获取数据。Promise是JavaScript 中最常见的推送方式。一个 promise(生产者)向注册的回调(消费者)传递一个被解析后的值,但与函数不同的是,promise 负责精确确定何时将该值推送到回调。
每个 Javascript 函数都使用 pull;该函数是数据的生产者,调用该函数的代码通过从其调用中提取单个返回值来使用它。
Observable
是多个值的生产者,并将它们推送给订阅者。我们订阅了一个 Observable,当下一个项目到达 onNext,或者当流完成 onCompleted,或者发生错误 onError 时,我们会收到通知。因为使用 Observable 我们会收到 onNext、onCompleted、onError 事件。我们可以做的其他事情是缓存,节流,……
Pull with Iterator vs Push with Observable
Iterator vs Observable in Java
Java 8 Streams API vs RxJava
让我们以 Java 8 Streams API (java.util.stream) 中的 Streams
和 RxJava
中的 Observables 为例(Java 的 ReactiveX API,用于使用可观察流进行异步编程)
- 我们可以使用 RxJava 执行异步任务
- 使用 Java 8 Stream,我们将遍历您的集合中的项
- 我们可以在 RxJava 中做几乎相同的事情(遍历集合的项),但由于RxJava 专注于并发任务,它使用同步,加锁等等,所以,使用RxJava的相同任务可能会比Java 8的Stream要慢
- RxJava 可以与 CompletableFuture 进行比较,但它可以计算不止一个值
- 默认情况下 RxJava 是单线程的,除非我们开始使用调度器,否则一切都会发生在同一个线程上
Backend implementation: REST method returning an Observable
One last thing: Streams vs. Collections
如您所见,我们的故事中有第四位玩家: Collections
。Java 8 Stream API 提供了一种处理 Java 集合的机制。它是关于将集合转换成流,并行处理元素,然后将结果元素收集到集合中.
- 集合是一种在内存中保存元素的数据结构。集合中的每个元素都是在它实际成为该集合的一部分之前计算出来的。因此,它是一组急于被计算的值。
- 流是固定的数据结构,可以按需计算元素。Java 8 Streams 可以看作是延迟构造的集合,其中的值是在用户需要时计算的。
- 与函数式编程语言一样,流支持可以串行或并行执行的聚合操作:filter、map、reduce、find、match、sort、limit、collect …
- Streams 还支持流水线和内部迭代:大多数 java 8 流操作只返回 Streams。这有助于我们创建一系列各种流操作→这称为流水线。流水线操作看起来类似于 SQL 查询