阅读 102

[译] 介绍响应式编程中的可观察者

对于新手程序员来说最具挑战性的事情之一就是学习观察者模式。了解如何有效地配合 RxJS 来使用它(观察者模式)处理异步数据,例如用户事件,HTTP 请求或者其他需要等待某些事情完成的事件是比较棘手的。

绝大多数人在新方式上花费时间和努力。新方式需要新的思维方法,可视化在这其中起着重要的作用。我们将数据当作随着时间推移而传递的一系列值而非每次取回的单个值。 这种思维方式被称作响应式编程。

由于观察者模式是一个由众多部分组成的巨大生态系统,所以本篇文章专注于可观察对象(Observable)。我将会很快通过其他文章来将观察者模式剩下的部分讲完,例如如何使用 RxJS 来处理。

我们将要讨论到的主题

  1. 异步究竟是什么?
  2. 该选择使用哪种模式(Obesever 或 Promise)
  3. 如何创建一个可观察对象
  4. 如何订阅一个可观察对象
  5. 如何取消订阅一个可观察对象

1. 异步究竟是什么?

对于 Web 和大多数语言而言有一件事的结果是你无法保证的,向服务器请求数据,例如用户列表。这里存在着不确定性因素。

其中的原因可能是数据不存在了、服务器损坏或者 HTTP URL 因为某人更改了查询字符串而失效。

对于上述以及其他的原因,我们需要异步处理这些数据。我们请求用户列表并等待数据被取回,但是这期间不停止整个程序的运行。

这就像发个消息给自己的同事去完成任务而不是将这个信息发给整个团队;发给整个团队是一个昂贵又不明智的方法。

让我们来纠正一个误解:同步、异步和多线程无关,多线程指的是同一时间执行多个操作。同步和异步仅仅是代表操作要么是依赖于彼此,要么是互相独立。

让我们对比同步和异步的不同来帮助我们理解它们究竟是如何工作的。

什么是同步?

同步事件要求当前任务完成之后才能转向下一个任务。

例: 你正在排队买电影票。这时你不能比排在你前面的人提前拿到电影票,这个规则同样适用于排在你后面的人。

什么是异步?

异步时间不需要你等待,你可以直接移动的下一个任务直到数据成功获取到。

例: 你和其他人坐在餐馆中。你为自己点了食物。其他人同样也可以为自己点食物,他们不需要等到你的食物做好并且端到你面前之后才能点自己的。在后厨,厨师不断地做饭服务和接受订单。食物一旦被做好就可以被送给相应的顾客。

总之,同步和异步规定了我们要么是等到操作完成再移至下一个任务,要么不用等待数据准备就绪直接移动至下一个任务。

该选择使用哪种模式(Obesever 或 Promise)

首先说明,观察者模式和承诺模式都是为了解决异步操作的。例如用户事件或者 HTTP 请求以及其他独立运行的事件。

当前大多数的操作都需要某种类型的同步或者异步处理方法,了解它的工作原理在构建强健应用中起着重要的作用。

这并没有代表你的生活变的更艰难了,反而是更容易了。虽然它的学习曲线有一些陡峭,但是最终的成效让一切变得值得。

保持单一模式

项目的复杂度决定了它们的不同。如果是简单应用,操作大多都是从服务器获取用户列表、展示活跃成员这类的,承诺模式(Promise)配合 Fetch API 就可以很好的解决问题。

但是如果你是在做大型复杂应用,包含很多异步操作例如改变数据、对数据流进行多种操作或者在多处复用。这类情况观察者模式更加适合。

能在同一个项目中使用两种模式吗?

可以,但是不推荐将处理同一件事的两种方式混在一起使用。相反,坚持一个并完全搞懂它才是最重要的事情。

利用 RxJS 提高你的技能

使用 RxJS 你可以使用 189 种操作符(文档中提到的)和其他很棒的资源。这些操作符都是通过简单的回调方式来处理数据流的。

如果你对 Javascript 的原型方法例如 map() filter() reduce() 熟悉的画,你会发现 RxJS 也有。注意,虽然概念相同,但是编写的代码并不一样。

这两种模式有什么不同呢?

观察者模式和承诺模式

上面是对两种设计模式的快速对比。关键不同点,Promise 每次只传递一个值供 .then() 回调函数使用。而 Observable 会将多个值作为随时间推移的数据序列发出。另一个重要的不同点是可观察对象可以取消或者重试而 Promise 不可以。但是,现在有一些第三方的包可以让 Promise 实现取消的功能。

3. 如何创建可观察对象

  • 从头创建一个可观察对象
  • 将 Promise 转化为可观察对象
  • 使用框架,例如 Angular,它在背后已经为你做好了

你知道 Angular 已经广泛地使用观察者模式了吗?所有的异步操作,例如 HTTP GET 或者监听事件在或者值变化都遵循观察者模式。

4. 如何订阅一个可观察对象

可观察对象只是一个数据集合,在它可以发出任何数据之前等待被调用(订阅)。如果你熟悉 Promise ,它获取数据的方式是链式调用 then() 方法或者使用 ES6 的 async/await

那么按照前面的例子,如何访问可观察对象传递的数据?

如上述所说,当我们订阅了一个可观察对象时,我们就是告诉了可观察对象要将它保存的一切传递给我们。可以是一个数组,一个事件集合或者一系列的对象等等。

我见过的开发者犯的最多的初级错误是他们在可观察者对象上做了一系列操作但是结果并不是他们想象的那样,没有拿到预期的结果。我也犯了很多次这个错误。记得先订阅。

5. 如何取消订阅一个可观察对象

取消订阅非常重要,否则会导致内存泄漏进而拖慢浏览器运行。如果你使用 Angular ,它提供了一个名为 asyncPipe 的管道可以帮助你自动订阅和取消订阅。

我们取消订阅的方式是我们通过创建变量来保存其当前状态来创建对每个Observable的引用。然后,对于每个变量,我们使用unsubscribe()方法将其链接。记住,只能在订阅后取消订阅。这很简单,但经常被遗忘。

总结

上文提到的,学习观察者模式最具挑战性的是思维方式的转变。观察者模式提供了一种新的思维方式,随着时间的推移而发出的一系列数据。本篇文章中,我们提到了多种创建可观察对象的方式以及如何订阅和取消订阅它。

我个人推荐使用观察者模式,因为它不仅提供了 Promise 模式的所有功能,并且还额外提供了 Promise 没有的。它还提供了一些很棒的操作符来防止用户发送无用的请求给后台。

其中的 debonceTime 给用户提供了足够的时间来填写一个完成的单词,然后只发送一次请求。你当然也可以使用 Promise 实现同样的功能,仅仅是多几行代码的事情。

我将在不久的将来介绍更多有关响应式编程的内容,敬请期待!

如果您有兴趣了解有关网络生态系统的更多信息,请参阅以下几篇文章,以提高您的网络技能。

关注下面的标签,发现更多相似文章
评论