首先贴上一个中文Rxjs文档链接,从官网被人直译下来的,也是比较全面的介绍rxjs了。最好的Rxjs中文文档
RXJS全名Reactive Extensions for JavaScript,JavaScript的响应式扩展。什么是响应式?响应式就是跟随时间不断变化的数据、状态、事件等转换成可被观察的序列,然后订阅那些变化,一旦变化则会执行业务逻辑。适用于异步场景。
RxJS所能解决的问题:
时刻保持响应。这对于一个应用来说意味着当他处理用户的输入或者凭借AJAX从服务器接受一些数据时停止是一件不可能接受的事情。在JavaScript中解决问题的方案始终是大量运用回调函数来进行一些运行的处理。但回调的使用使内容丰富的大型应用变得凌乱,一旦你需要多块数据时你就陷入了回调地狱。Angular2中,组件间通讯@Output对应的EventEmitter实际上就是一个Subject(主题:同时为Observable和Observer);Http模块中Observable作为大部分API的交互对象使用。但是这只是官方的外部扩展,并不必须,也可以使用.toPromise的方式转换为Promise来使用或第三方扩展库或Fetch API 传统Ajax已死,Fetch永生。
RxJS初探:
RxJS是一个解决异步问题的JS开发库.它带来了观察者模式和函数式编程的相结合的最佳实践。 观察者模式是一个被实践证明的模式,基于生产者(事件的创建者)和消费者(事件的监听者)的逻辑分离关系.况且函数式编程方式的引入,如说明性编程,不可变数据结构,链式方法调用会使你极大的简化代码量。RxJS 引入了一个重要的数据类型——流(stream)。流(Streams)无非是随时间流逝的一系列事件。流(Streams)可以用来处理任何类型的事件,如:鼠标点击,键盘按下,等等。你可以把流作为变量,它有能力从数据角度对发生的改变做出反应。
Stream
流(Streams)无非是随时间流逝的一系列事件。流(Streams)可以用来处理任何类型的事件,如:鼠标点击,键盘按下等等。你可以把流作为变量,它有能力从数据角度对发生的改变做出反应。
1 | var a = 2; |
事件引发的改变总是从事件源(生产者),向下传递到所有事件监听方(消费者)。如果变量看做流呢,又是什么结果呢?
1 | var A$ = 2; |
流的方式重新定义的变量值的动态行为.换句话说,C$是把两个流变量A$和B$进行合并操作。当一个新值被推进了A$,C$立刻响应式的变更为16。
开始了解RxJS中的几个重要成员
- Observable可观察对象:表示一个可调用的未来值或者事件的集合。
- Observer观察者:一个回调函数集合,它知道怎样去监听被Observable发送的值
- Subscription订阅: 表示一个可观察对象的执行,主要用于取消执行。
- Operators操作符: 纯粹的函数,使得以函数编程的方式处理集合比如:map,filter,contact,flatmap。
- Subject(主题):等同于一个事件驱动器,是将一个值或者事件广播到多个观察者的唯一途径。
- Schedulers(调度者): 用来控制并发,当计算发生的时候允许我们协调,比如setTimeout,requestAnimationFrame。
第一个例子
使用RxJS创建一个可观察对象:
1
2
3
4
5var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.scan(count => count + 1, 0)
.subscribe(count => console.log(`Clicked ${count} times`));observable可观察对象,以惰性的方式推送多值的集合
下面的例子是一个推送1,2,3,4数值的可观察对象,一旦它被订阅1,2,3,就会被推送,4则会在订阅发生一秒之后被推送,紧接着完成推送
1
2
3
4
5
6
7
8
9var observable = Rx.Observable.create(observer=>{
observer.next(1);
observer.next(2);
observer.next(3);
setTimeout(() => {
observer.next(4);
observer.complete();
}, 1000);
});Pull拉取 VS Push推送
拉和推是数据生产者和数据的消费者两种不同的交流协议(方式);
什么是”Pull拉”?在”拉”体系中,数据的消费者决定何时从数据生产者那里获取数据,而生产者自身并不会意识到什么时候数据将会被发送给消费者。
每一个JS函数都是一个“拉”体系,函数是数据的生产者,调用函数的代码通过“拉出”一个单一的返回值来消费该数据(return 语句)。
什么是”Push推”?在推体系中,数据的生产者决定何时发送数据给消费者,消费者不会在接收数据之前意识到它将要接收这个数据。
Promise(承诺))是当今JS中最常见的Push推体系,一个Promise(数据的生产者)发送一个resolved value(成功状态的值)来注册一个回调(数据消费者),但是不同于函数的地方的是:Promise决定着何时数据才被推送至这个回调函数。
RxJS引入了Observables(可观察对象),一个全新的”推体系”。一个可观察对象是一个产生多值的生产者,并”推送给”Observer(观察者)。
RxJS VS Promise—3个最重要的不同点
不同点 | Rxjs | Promise |
---|---|---|
动作是否可以取消? | 是 | 否 |
是否可以发射多个值? | 是 | 否 |
各种工具函数? | 是 | 否 |
Operators操作符
create() 创建一个可观察序列,参数为一个封装数据生成逻辑的函数,该函数的参数为观察者
empty() 不需要传递参数,创建一个空序列并立即结束
1 | Rx.Observable.empty() = Rx.Observable.create((o)=>{ |
never() 不需要传递参数,创建一个空序列,并永远不结束
1 | Rx.Observable.never() = Rx.Observable.create((o)=>{ |
throw() 创建一个空序列,参数来声明错误并立即抛出错误
1 | Rx.Observable.throw('error') = Rx.Observable.create((o)=>{ |
range() 创建一个有线长度的整数序列,两个参数,第一个起始值,第二个元素数量
1 | Rx.Observable.range(30,4) //输出:30,31,32,33 |
interval() 创建一个无限长度的周期性序列
1 | Rx.Observable.interval(1000) //输出:0,1,2... |
timer() 指定一个额外的参数来调节第一值的静默时长,第二个参数可选,若无则仅仅在规定的静默时长后输出一个值,然后结束序列
1 | Rx.Observable.timer(0,1000) //输出:0,1,2... |
from() 可以将已有的数据转化为Observable,参数为iterable数据集对象,常见Array,String
1 | Rx.Observable.from(iterable) |
of() 不在同一个数据集中的多个来源的数据,使用of()方法直接构造:
1 | Rx.Observable.of([1,2,3]) // [1,2,3] |
just() 将任何数据转化为一个单值输出的Observable
1 | Rx.Observable.just([1,2,3]) // [1,2,3] |
repeat() 创建一个重复值序列 par1:值,par2:次数
1 | Rx.Observable.repeat('a',2) // a a |
fromEvent() 将事件流转化为Observable,
1 | var el = document.getElementById("btn"); //DOM对象作为事件源 |
toArray() 将序列还原为数组对象,只有在订阅后才还原为数组
1 | var source = Rx.Observable.of(1,2,3,4); //序列:1 2 3 4 |
delay() 推迟 参数为数字或Date对象
delaySubscription() 延迟订阅 参数同理
startWith() 可以在源序列之前添加额外的元素
1 | var source = Rx.Observable.of(1,2,3); //序列:1 2 3 |
map() 对源序列进行变换,并返回新的序列(改变了源)
1 | var trandform = function(item){ |
concat() 有序拼接 merge()无序
1 | var source = Rx.Observable.of(1,2,3); //序列:1 2 3 |
concatAll() 如果源序列的元素也是序列 —— 序列的序列,那么可以使用concatAll() 方法将各元素序列按顺序拼接起来
1 | var source = Rx.Observable.of(10,20,30) |
catch() 捕捉源序列错误,返回新序列
1 | var source = Rx.Observable.create(function(o){ |
pluck() 针对元素为json对象的源序列,返回指定属性的值的序列
1 | var source = Rx.Observable.of({name:'john',age:33},{name:'lee',age:22}); |
flatMap() 平坦化映射:首先将一个序列的各元素映射为序列,然后将各序列融合 参数是一个映射函数,返回值为序列
1 | var source = Rx.Observable.of(10,20); |
flatMapLatest() 与flatMap()的区别在于将最新的序列中的元素输出
concatMap() 将源序列各元素映射为序列,然后按顺序拼接 (与flatMap的区别所在)
1 | var source = Rx.Observable.of(1,2,3); |
flatMap与map异同点
Map用于对自身对象数值进行映射,将发射对象转换成另一个发射对象发射,返回一个包含映射结果的Observable对象。而flatMap是把自身对象里的数值进行映射并转换成一个新的Observable对象.当从其他类型对象中构建Observable对象时,需要使用flatMap方法
flatMap与concatMap异同点
merge和map结合与concat和map结合的区别,归根结底为merge与concat的区别,一个无序一个有序
filter() 筛选源序列中满足条件的元素,并返回新的序列
1 | var source = Rx.Observable.of(1,2,3,4,5); //序列: 1 2 3 4 5 |
skip(num) 抑制序列头部元素数量输出 skipLast(num)尾部 skipWhile(if)指定一个条件
take(num) 截取序列头部元素数量输出 takeLast(num)尾部 takeWhile(if)指定一个条件
distinct 去重,并返回一个新序列
1 | var source = Rx.Observable.of(1,2,3,4,2,1); //序列: 1 2 3 4 2 1 |
distinctUntilChanged 去重,并返回一个新序列
1 | var source = Rx.Observable.of(1,2,2,3,4,2,1); //序列: 1 2 3 4 2 1 |
debounce 去抖动,一段时间内只取最新数据作为一次发射数据,其他数据取消发射
throttle(和debounce唯一区别是debounce取一段时间内最新的,而throttle忽略这段时间后,发现新值才发送, 通俗讲,都设定一个时间周期,持续触发事件,throttle为每到时间周期便会触发一次,bebounce为触发周期小于设定时间周期不予事件触发)
buffer() 使用第二个序列触发源序列中多个元素的打包
1 | var source = Rx.Observable.timer(0,1000); //序列:0 1 2 3 ... |
bufferWithTime() 按固定时间间隔对源序列进行打包
1 | var source = Rx.Observable.timer(0,1000); //序列:0 1 2 3 ... |
zip() 支持可变数量的序列作为参数,最后一个参数应当是一个组合函数, 其返回值将作为目标序列的元素
1 | var source1 = Rx.Observable.of(1,2,3); //序列: 1 2 3 |
forkJoin() 将多个序列的最后一个元素组合为一个数组后,作为目标序列的唯一元素
1 | var source1 = Rx.Observable.of(1,2,3); //序列: 1 2 3 |
combineLatest() 将多个序列的最后一个元素,使用组合函数构成目标序列的一个新元素
1 | var source1 = Rx.Observable.interval(200).map(x => 'First:' + x) |