Rxjs常见操作符

一.RxJS初试

  • 在javascript中的试炼

    const height = document.getElementById('height');
    const height$ = Rx.Observable.fromEvent(height, 'keyup');//$是约定俗称的命名方式,因为通过Rx.Observable已经将其转换成了流形式,其中含义是:将keyup事件转换成了Observable观察者
    //既然是观察者,则可以订阅
    height$.subscribe(val => console.log(val));//当输入的时候会输出事件的对象,获得值则使用val.target.value
    // 输入是1,console打印的就是1
    
    
  • RxJs的威力在于合并和转换流,实例如下

    • html

      
      
      
    • js

      const length = document.getElementById('height');
      const width = document.getElementById('width');
      const area = document.getElementById('area');
      const length$ = Rx.Observable.fromEvent(length, 'keyup').pluck('target','value');
      const width$ = Rx.Observable.fromEvent(width, 'keyup').pluck('target','value');
      //combineLatest表示如果监听的两个值有一个改变则会重新计算一遍
      const area$ = Rx.Observable.combineLatest(length$, width$, (l,w)=>{return l*w});//用于将两个流合并成一个数据流
      area$.subscribe(val => area.innerHTML = val);
      
      
  • 事件流:理解Rx的关键是要把任何变化想象成事件流

二.RxJS常见操作符

1.常见创建类操作符

  • from:可以把数组、Promise、以及Iterable转化为Observable
  • fromEvent:可以把事件转化为Observable
  • of:接受一系列的数据,并把它们emit出去
    • 如可以使用object$ = Rx.Observable.of({id:1,value:20})转化对象,使用的时候应该是object. v a l u e 或 o b j e c t .value或object.value或object.id的方式

2.常见转换操作符

  • map

    • 是mapTo、pluck操作符的根本

    • 举例将上述pluck操作符取target的value值转换成使用map操作符

      const width$ = Rx.Observable.fromEvent(width, 'keyup').map(ev=>ev.target.value);
      
      
    • 在angular中灵活使用Observable如下

      // 定义一个发起网络请求获取Observable的方法
      getQuote():Observable {
          const uri = 'http://localhost:3000';
          return this.http.get(uri)
                  .map(res => res.json() as Quote);// 将请求返回的内容转换成json并转换成对应定义的Quote对象
      }
      
      
  • mapTo

    • 比如点击按钮事件或其他事件,我们不需要关注其值内容,只需要知道发生了即可,可以使用mapTo定义成一个固定值

    • 实例代码

      const width$ = Rx.Observable.fromEvent(width, 'keyup').mapTo(1);//此时执行keyup事件,width$的值即为1
      //等同于如下
      const width$ = Rx.Observable.fromEvent(width, 'keyup').map(_ => 1);//此时执行keyup事件,width$的值即为1
      
      
  • pluck

3.Observable的性质

  • Observable有三种状态(即subscribe的三个参数):next、error、complete
    • next是正常执行时的内容,subscribe的第一个参数
    • error是当执行时出错,或监听了throw类型Observable时的执行内容,subscribe的第二个参数
    • complete是Observable执行结束时的内容,subscribe的第三个参数
  • 特殊的Observable:永不结束、Never、Empty(结束但不发射)、Throw
    • Never类型Observable表示不会发生也永远不会结束,会在执行过程中导致,也可直接通过Rx.Observable.error('xxx')的方式声明,结果不会执行next、error、complete中任何一个阶段
    • Empty类型Observable不会发射元素会直接结束,会在执行过程中导致,也可以通过Rx.Observable.empty()的方式声明,结果不会执行next、error,会执行complete阶段
    • Throw类型Observable直接进入error状态,会在执行过程中抛出异常导致,也可以直接通过Rx.Observable.throw('xxx')的方式声明,结果只会执行error阶段

4.常见工作操作符:do

  • do操作符用于在流处理期间对数据进行操作,实例如下

    const interval$ = Rx.Observable.interval(100)
    .do(v => {
        console.log('val is :'+v);    
    })
    .take(3);
    
    

5.常见变换类操作符:scan

  • scan(()=>{})接受一个函数,参数1是上次处理后的结果,参数2是新值内容。实例代码

    const interval$ = Rx.Observable.interval(100)
    .filter(v => val%2 === 0) //表示是偶数才放行
    .scan((x,y)=>{return x+y})//表示结果累加操作
    .take(4);
    //输出结果
    // 0[0+0]
    // 2[上次结果0+新值2]
    // 6[上次结果2+新值4]
    // 12[上次结果6+新值6]
    //complete执行内容
    
    

6.常见数学类操作符:reduce

  • reduce是将流计算结果做统一的最后处理并发射,实例代码

    const interval$ = Rx.Observable.interval(100)
    .filter(v => val%2 === 0) //表示是偶数才放行
    .take(4)
    .reduce((x,y)=>{return x+y});
    //输出结果
    // 12[只发射最终值]
    
    

7.过滤类操作符:filter、take、first/last、skip…

  • take(num)表示取流中前num个

  • filter(()=>{})表示对流处理的放行判断,如果满足条件则放行,不满足条件则不放行

    const interval$ = Rx.Observable.interval(100)
    .filter(v => val%2 === 0) //表示是偶数才放行
    .take(3);//订阅后会输出0 2 4
    
    
  • first()表示取流第一个,相当于take(1)

  • last()表示取流最后一个

  • skip(num)表示跳过前num个

    const interval$ = Rx.Observable.interval(100)
    .filter(v => val%2 === 0) //表示是偶数才放行
    .skip(2);//订阅后会输出4 6 8 ...
    
    

8.常见创建类操作符:Interval、Timer

  • Interval实例代码

    const interval$ = Rx.Observable.interval(100).take(3);
    interval$.subscribe(
        val => {
            console.log(val) //next状态
        },
        err => {
            console.log(err) // error状态
        },
        ()=> {
            console.log('I am complete') // complete状态
        }
    );
    //输出结果:interval()是做循环用的,每次发射出来的是索引,故生成的是0/1/2/3/4....,又由于take表示取前多少个,故take(3)表示取前3个
    // 0
    // 1
    // 2
    // "I am complete" // complete状态执行的内容
    
    
  • Timer实例代码

    const timer$ = Rx.Observable.timer(100,200);//表示100毫秒之后启动,之后以200毫秒的频率一直发送
    // 故timer比Interval多出起始延迟时间的设置
    timer$.subscribe(v=> console.log(v))
    //输出结果
    // 0 --运行后100毫秒之后输出
    // 1 --输出0后200毫秒之后输出
    // 2 --输出1后200毫秒之后输出
    // 3 --...
    
    

9.实例:自行给rxjs中Observable添加debug方法

  • 通过Observable的原型中定义debug方法返回Observable对象

    import {Observable} from 'rxjs/Observable';
    import {environment} from '../../environment/environment'
    // typescript用于解决自行添加对象属性的报错问题
    declare module 'rxjs/Observable' {
        interface Observable {
            debug: (...any) => Observable;
        }
    }
    // 给Observable添加debug方法
    Observable.prototype.debug = function(message:string) {
        return this.do(
            (next)=>{
                if(!environment.production) {
                    console.log(message,next)
                }
            },
            (err) => {
                if(!environment.production) {
                    console.error('ERROR>>',message,err);
                }
            },
            ()=> {
                if(!environment.production) {
                    console.log('Completed -');
                }
            }
        )
    }
    //使用时直接在声明Observable期间添加即可以查看对应Observable对象内容,如
    this.http.get('url')
        .debug('Test:')
        .map(res => res.json() as Quote);
    //在subscribe监听后的会输出对应的log
    
    

10.过滤类操作符:debounce、debounceTime

  • debounce:比debounceTime灵活,debounceTime只能设定固定的毫秒间隔,而debounce可以通过接受的function设定毫秒间隔

    const length$ = Rx.Observable.fromEvent(length,'keyup').pluck('target','value').debounce(()=>Rx.Observable.interval(300));//可以自行修改function返回内容从而决定滤掉的内容
    //上述代码含义是:过滤掉300毫秒以内keyup事件监听内容
    
    
  • debouceTime(num):时间滤波器,表示只关注大于等于num毫秒间隔的事件内容

    const length$ = Rx.Observable.fromEvent(length,'keyup').pluck('target','value').debounceTime(300);
    //上述代码含义是:过滤掉300毫秒以内keyup事件监听内容
    
    
  • 执行图片


    在这里插入图片描述

11.过滤类操作符:distinct、distinctUtilChanged

  • distinct:整个序列中,过滤一样的,保留不一样的(要求序列中没有重复的元素)

    const length$ = Rx.Observable.fromEvent(length,'keyup').pluck('target','value').distinct();//过滤掉整个流中重复的元素
    
    
  • distinctUtilChanged:只跟前一个元素比,过滤一样的,保留不一样的

    const length$ = Rx.Observable.fromEvent(length,'keyup').pluck('target','value').distinctUtilChanged();//过滤掉流中前一个重复的元素
    
    
  • 执行图片


    在这里插入图片描述

12.合并类操作符:merge、concat、startWith

  • merge:在整个序列中按照流运行状态进行合并

  • concat:在整个序列中将流前后拼接(如拼接的第一个流是无尽流,则永远只会输出第一个流内容,因为第二个流永远不会发生,第一个流没有执行完)

  • startWith:设定流发射的初始值

  • 执行图片


    在这里插入图片描述

13.合并类操作符:combineLatest、withLatestFrom、zip

在这里插入图片描述
  • 通过combineLatest可以对两个流进行对应的处理操作,实例请参照开头计算面积

  • zip有对齐的感觉,将两个流对应位置的元素进行处理操作,慢的流决定最终zip生成流的速度

  • withLatestFrom当基准流改变时才会进行流处理,使用方式是基准流.withLatestFrom(其他流),如下

    const merged$ = length$.withLatestFrom(width$);
    
    
  • 区别:zip有对齐的特性,withLatestFrom是以源事件流为基准,combineLatest是无论任何一个流发生改变时都会处理

你可能感兴趣的:(Rxjs常见操作符)