推荐我的Rxjs教程:Rxjs系列教程目录
前言
随着开发中项目的越来越大,代码的要求越来越高,于是开始四处搜找各种js库进行学习。为了学习代码行为模式,例如:竞争等等。在技术总监的指引下找到Rxjs进行学习,再次表以感谢。在看教程时,有很多地方不解,于是用博客做以记录,并将自己的经验以尽可能简单的方式分享给大家。
这里简单解释一下Rxjs,RxJS 是一个js库,它通过使用 observable 序列来编写异步和基于事件的程序。ReactiveX 结合了 观察者模式、迭代器模式 和 使用集合的函数式编程,以满足以一种理想方式来管理事件序列所需要的一切。看到这你肯定疑问它有什么用?你先放下这个疑问,先看看一个简单的案例。
Observable可观察对象
Observable可观察对象:表示一个可调用的未来值或者事件的集合。
一个例子
通常你这样注册事件监听:
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));
使用RxJS创建一个可观察对象:
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('Clicked!'));
看到这段代码你可能迷茫,这是什么意思?难道只是换了一种写法?
观察者模式
要说Observable可观察对象首先得说说:观察者模式
。
观察者模式
又叫发布-订阅(Publish/Subscribe)模式
:
他定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象(也可叫做抽象的通知者)。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。而且各个观察者之间相互独立。
观察者模式的结构中包含四种角色:
(1)抽象主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。
(2)抽象观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。
(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
观察者模式结构的类图如下所示:
在现实生活中,我们经常用它来“放风”,比如:上自习时,老师不在我们在玩,派出一个同学看老师,老师来了通知大家;如果该同学没有发现老师,老师“咳咳”两声通知大家自己来了让大家安静自习,然后批评一番。
这里的监听的抽象主题对象是“老师是否来了”,同学们是观察者,同学们依赖主题对象的状态并且是一种一对多的依赖关系,同学们同时监听主题对象的反馈结果,同学们订阅(观察)这个主题,在这个主题发生变化时,来更新自己:
老师来了->安静自习,写作业。
老师没来->该玩玩,该吃吃。
放风的同学发现老师会通知,放风的同学没发现,老师进入教室老师自己也会“咳咳”两声通知。因此“老师是否来了”这个抽象主题中,老师通知和放风的同学通知都是这个抽象主题对象的具体实现,这个抽象主题对象就是可观察对象(可以观察嘛~~~),这时再想想前面对于可观察对象的定义(可调用的未来值或者事件的集合)是不是明白了?
同样上面的RxJS的代码也是这种效应,Rx.Observable.fromEvent(button, 'click')
是一个创建一个点击事件的可观察对象,然后使用subscribe(() => console.log('Clicked!'));
订阅这个可观察对象,其中() => console.log('Clicked!')
是一个观察者,如果发生点击事件主题对象的状态会发生改变,而他则会被执行。
这样有什么好处呢?
- 我们只需要针对可观察对象这一抽象的主题对象接口编程,减少了与具体的耦合,即他只是一个抽象的通知者。
- 观察者只依赖主题对象的状态,这意味着维持各个观察者的一致性,但又保证了各个观察者是相互独立的。
发布-订阅
Observables(可观察对象)
以惰性的方式推送多值的集合。
示例 - 当订阅下面代码中的 Observable 的时候会立即(同步地)推送值1、2、3,然后1秒后会推送值4,再然后是完成流(即完成推送):
var observable = Rx.Observable.create(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
setTimeout(() => {
observer.next(4);
observer.complete();
}, 1000);
});
要调用 Observable 并看到这些值,我们需要订阅 Observable:
console.log('just before subscribe');
observable.subscribe({
next: x => console.log('got value ' + x),
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done'),
});
console.log('just after subscribe');
结果如下:
just before subscribe
got value 1
got value 2
got value 3
just after subscribe
got value 4
done
拉取 (Pull) vs. 推送 (Push)
拉取和推送是两种不同的协议,用来描述数据生产者 (Producer)
如何与数据消费者 (Consumer)
如何进行通信的。
什么是拉取? - 在拉取体系中,数据的消费者</