1.高阶操作符
高阶操作符和高阶函数或高阶组件的定义是一样的,高阶操作符表示一个可观察对象返回另一个可观察对象
定义形式为:
Observable<Observable<T>> --> Observable<T>
示例:
var clickObservable = Rx.Observable.fromEvent(document, 'click') // 普通Observable
// 这个可观察对象返回另一个可观察对象
var clockObservable = clickObservable
.map(click => Rx.Observable.interval(1000)) // 高阶Observable
clockObservable.subscribe( // clockObservable是一个可观察对象
clock => clock.subscribe(x => console.log(x)) // clock是一个可观察对象
)
上面的示例可以看出我们需要嵌套 subscribe
, 这样写起来很复杂,RxJS为我们提供了 flatten
的操作符
switch
这个操作符接收一个 Observable<number>
类型的可观察对象,并且返回一个Observable<number>
类型的可观察对象,使用 switch 之后将自动unsubscribe上一个Observable
上面示例可以改写为:
var clickObservable = Rx.Observable.fromEvent(document, 'click')
var clockObservable = clickObservable
.map(click => Rx.Observable.interval(1000)) // Rx.Observable.interval(1000) 为Observable<number>
.switch() // 这个操作符将嵌套的Observable flatten
// switch 的 maple digram
// Observable<Observable<number>> --> Observable<number>
/*
------+----------+--------------- // 'click' Observable
\ \
-0-1-2-3-4 -0-1-2-3-4-5... // 使用 '\' 表示 'click' Observable 内部的 Observable
switch // 操作符, 对Observable对象进行flatten
--------0-1-2-3-4--0-1-2-3-4-5... // 使用 switch 之后将自动unsubscribe上一个Observable
*/
clockObservable.subscribe(x => console.log(x)) // 现在不用嵌套
这个和上面示例的不同之处在于,第2次点击时,第一次订阅的将自动unsubscribe
mergeAll
这个和switch的区别就是不会取消上一个Observable,另外可以限制Observable同时运行的数量
mergeAll(observableNum?: number)
示例:
var clickObservable = Rx.Observable.fromEvent(doucment, 'click');
var clockObservable = clickObservable.map(click => Rx.Observable.interval(1000))
.mergeAll() // 此处没有传参,不限制Observable的数量
// maple
/*
------+----------+--------------- // 'click' Observable
\ \
-0-1-2-3-4 -0-1-2-3-4... // 使用 '\' 表示 'click' Observable 内部的 Observable
mergeAll // 操作符
--------0-1-2-3-4-5061728394...
*/
可以看出 mergeAll 并没有unsubscribe 上一个Observable
// 另外假如传入数量
var clickObservable = Rx.Observable.fromEvent(doucment, 'click');
var clockObservable = clickObservable.map(click => Rx.Observable.interval(1000))
.mergeAll(2) // 允许最多同时有2个Observable
// 第3次点击并不会产生Observable
concatAll
这个操作符表示将Observable一个接着一个的往后添加变为一个Observable,其内部原理其实就是 mergeAll(1)
var clickObservable = Rx.Observable.fromEvent(doucment, 'click');
// 这里的Observable是有限个数
var clockObservable = clickObservable.map(click => Rx.Observable.interval(1000).take(5))
.mergeAll(1)
// maple
/*
------+--------------+---+-------- // 'click' Observable
A B C // A, B, C 表示3次点击产生的Observable
\
-0-1-2-3-4| //
mergeAll(1) // 只允许同时最多有一个Observable运行
------0-1-2-3-4-------0-1-2-3-4----0-1-2-3-4|
A B C // A结束 B开始; B结束 C开始
*/
这个被 concatAll()
封装
var clickObservable = Rx.Observable.fromEvent(doucment, 'click');
// 这里Observable是有限个数
var clockObservable = clickObservable.map(click => Rx.Observable.interval(1000).take(5))
.concatAll() // 此处没有传参,不限制Observable的数量
// maple
/*
------+--------------+---+-------- // 'click' Observable
A B C // A, B, C 表示3次点击产生的Observable
\
-0-1-2-3-4| //
concatAll() // 本质上就是 mergeAll(1)
------0-1-2-3-4-------0-1-2-3-4----0-1-2-3-4|
A B C // A结束 B开始; B结束 C开始
*/
2.高阶操作符语法糖
switchMap
等价于 map ... + ... switch ...
, 很重要!!!
上面的例子中
var clickObservable = Rx.Observable.fromEvent(document, 'click') // 普通的Observable
var clockObservable = clickObservable
.map(click => Rx.Observable.interval(1000)) // 高阶Observable
.switch() // 普通的Observable
可以看出这个过程为: 普通的Observable --> 高阶Observable --> 普通的Observable
switchMap
就是对上面 高阶Observable --> 普通的Observable
进行包装的语法糖
var clickObservable = Rx.Observable.fromEvent(document, 'click') // 普通的Observable
var clockObservable = clickObservable
.switchMap(click => Rx.Observable.interval(1000)) // 高阶Observable
# switchMap
// Observable<Event> --> Observable<number>
因为 switch
会unsubscribe (也可以称之为 '取消') 前面的Observable, 利用这一点在实际项目中我们如果发起多次网络请求,可以使用 switchMap()
来取消先前的请求
// 返回一个promise
const performRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())
const clickObservable = Rx.Observable.fromEvent(document, 'click')
// Observable<Event> --> Observable<Promise<Response>> --> Observable<Response>
const responseObservable = clickObservable
.switchMap(click => Rx.Observable.fromPromise(performRequest()))
responseObservable.subscribe(res => console.log(res.email))
实际上 switchMap
可以将Observable<T>
--> Observable<Observable<T>>
--> Observable<T>
, 也可以将promise
转换为 Observable<T>
所以上面的例子可以写为:
const performRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())
const clickObservable = Rx.Observable.fromEvent(document, 'click')
// Observable<Event> --> Observable<Response>
const responseObservable = clickObservable
.switchMap(click => performRequest()) // 直接将promise 进行转换
responseObservable.subscribe(res => console.log(res.name))
// "Leanne Graham"
mergeMap
mergeMap
是RxJS5中的, RxJS4中使用 flatMap
, 当然RxJS5中也可以使用flatMap
这个操作符是 map... + ...mergeAll
的语法糖,等一个Observable结束,然后再开始下一个Observable
语法:
public mergeMap(project: function(value: T, ?index: number): ObservableInput, resultSelector: function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any, concurrent: number): Observable
示例:
const proformRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())
const clickObservable = Rx.Observable.fromEvent(document, 'click')
const responseObservable = clickObservable
.mergeMap(click => performRequest())
responseObservable.subscribe(res => console.log(res.name))
另外2个可选参数为:
const proformRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())
const clickObservable = Rx.Observable.fromEvent(document, 'click')
// (click, res) 'click' 表示clickObservable res表示promise返回的response对象
// 3: 表示允许最大并行的Observable数量
const nameObservable = clickObservable
.mergeMap(click => performRequest(), (click, res) => res.name, 3)
// 此处直接可以使用name, 因为上面(click, res) => res.name 将其进行了处理
nameObservable.subscribe(name => console.log(name))
concatMap
同样的这个等同于:
concatMap === map... + ...concatAll
// 或者
concatMap === map... + ...mergeAll(1)
另外这个操作符也可以添加第2个可选参数 resultSelector: function(outerValue: T, innerValue: I, outerIndex: number, innerIndex: number): any
示例:
const proformRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())
const clickObservable = Rx.Observable.fromEvent(document, 'click')
const nameObservable = clickObservable
.concatMap(click => performRequest(), (click, res) => res.name)
# 或者
// const nameObservable = clickObservable
// .mergeMap(click => performRequest(), (click, res) => res.name, 1)
nameObservable.subscribe(name => console.log(name))