RxJS 的一些使用及简单理解
前言
这阵子在看 Angular ,谷歌的东西看着确实很让人感兴趣
虽然感觉国内公司用的不多
在写一些简单的 demo 时, 返回 Observable 对象很常见
so,一边学习 Angular ,一边来看 RxJS 的文档来学习学习
正文
RxJS 全称 Reactive JavaScript ,官方仓库:ReactiveX / rxjs
在 RxJS 文档中,我们开始其实只需要理解下面几个概念即可
ObservableObserverSubscription
理解上面的三个概念之后就可以愉快地使用 RxJS 了
Observable 和 Observer
Observable 为可观察对象,简单点理解,这个对象可以产生一些值供使用
1 | import { Observable } from "rxjs"; |
如何去获取 next 出来的值呢,这就要使用 subscribe 这个方法了
subscribe 需要我们传入一个 Observer 对象,使得我们能够取到 next 出来的数据
Observer 对象可以简单理解为一个包含了 next ,complete ,error 函数的简单对象即可
1 | // 上个片段代码... |
效果如下:

是不是莫名觉得有点熟悉,是的,很像 Promise
上面的代码可以理解为以下代码
1 | const promise = new Promise((resolve, reject) => { |
那么 Promise 和 Observable 有什么不同的?
Promise 和 Observable 的不同
多次生成值
Observable 可以多次生成值,而 Promise 只能生成一次值。在传入 Observable 的函数中,通过 subscriber.next 函数可以多次生成值,结束的标志是调用 subscriber.complete 函数
1 | import { Observable } from "rxjs"; |
上下文隔离
对于每一次对 Observable 的 subscribe 调用,都会是一个新的上下文,而 Promise 对于多个 then 调用只有一个上下文
这点看起来不是很容易理解,写个代码就很清晰了
Observable 例子
1 | import { Observable } from "rxjs"; |
效果如下:

Promise 例子
1 | const promise = new Promise((resolve, reject) => { |
效果如下:

从这两个结果我们可以看出,调用 subscribe 函数会重新运行传入 Observable 的函数来生成一份新的上下文,而 Promise 只会执行一次传入的回调
不支持链式调用
Observable 是不支持链式调用的,因为调用 subscribe 的返回值并不是 Observable ,而是 Subscription (这个后面会讲到), 而 Promise 支持

回调同步执行
- 执行传入
subscribe的函数的时机取决于传入Observable函数的上下文,而Promise中通过then注册的函数会延迟到本轮的微任务队列中再执行
Observable 例子
1 | import { Observable } from "rxjs"; |
效果如下:

Promise 例子
1 | const promise = new Promise((resolve, reject) => { |
效果如下:

通过例子,可以看出,不管如果 Observable 存在同步的 next 还是异步的 next , observer 的回调都会在这个 next 之后立即执行
构造器传入函数延迟执行
传入 Observable 的函数只有在调用 subscribe 之后,才会执行,而 Promise 会在初始化对象时就会执行传入的函数
1 | import { Observable } from "rxjs"; |
效果如下:

Subscription
在上面的对比中,我们提到 Observable 是不支持链式调用的,即调用 subscribe 返回的对象不是 Observable ,而是 Subscription
Subscription 对象只有一个方法,就是 unsubscribe ,这个方法用来取消 某个 Observer 对 Observable 的观察
不过前面我们都没用到这个功能,我们可以换个例子
1 | import { Observable } from "rxjs"; |
上面的例子为每一秒 next 出一个值
但是有个问题是,当我们不想要它继续产生值的话,我们可能会这样写
1 | import { Observable } from "rxjs"; |
当然这样写有一个很明显的问题,就是我们和外界的变量耦合了,这会影响系统的稳定性
所以我们可以换成下面的写法
1 | import { Observable } from "rxjs"; |
可以简单理解为这个 Subscription 对象就是为了释放占用的资源
当然,如果 Observable 的结束是可以预测的话,即我们能够去调用 complete 方法,也是会执行内部返回的函数
1 | import { Observable } from "rxjs"; |
上面的例子会输出 0 1 2 3 4 clear timer
但是如果 Observable 的结束无法预测,比如上面的这个包装 setInterval 例子,这时候只能通过手动调用 unsubscribe 来清除定时器