#3 高阶操作符

1.高阶操作符

高阶操作符和高阶函数或高阶组件的定义是一样的,高阶操作符表示一个可观察对象返回另一个可观察对象

定义形式为:

Observable> --> Observable

示例:

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 类型的可观察对象,并且返回一个Observable 类型的可观察对象,使用 switch 之后将自动unsubscribe上一个Observable

上面示例可以改写为:

var clickObservable = Rx.Observable.fromEvent(document, 'click')

var clockObservable = clickObservable
            .map(click => Rx.Observable.interval(1000)) // Rx.Observable.interval(1000) 为Observable
            .switch() // 这个操作符将嵌套的Observable flatten

// switch 的 maple digram
// Observable> --> Observable
/*
------+----------+---------------    // '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 --> Observable            

因为 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 --> Observable> --> Observable
const responseObservable = clickObservable
                            .switchMap(click => Rx.Observable.fromPromise(performRequest()))
                            
responseObservable.subscribe(res => console.log(res.email))                            

实际上 switchMap 可以将Observable --> Observable> --> Observable, 也可以将promise 转换为 Observable

所以上面的例子可以写为:

const performRequest = () => fetch('http://jsonplaceholder.typicode.com/users/1').then(res => res.json())

const clickObservable = Rx.Observable.fromEvent(document, 'click')

// Observable --> Observable
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))                             

你可能感兴趣的:(#3 高阶操作符)