RxJS操作符(二)

take()自动取消订阅,可以终止Observable和Observe之间的订阅关系。

一、Observable的性质

三种状态:nex, error, complete

 

进入到Error状态:

const interval$ = Rx.Observable.interval(1000)
.filter(val=>{
  throw '出错了'
})
.take(4)
.reduce((x,y)=>{//reduce接收函数作为参数
  return [...x,y];
},[])

interval$.subscribe(
  val=>console.log(val),
  err=>console.error('Error:' + err),
  ()=>console.log('I am complete')
);

 

 

二、特殊类型的Observable

  • 永不结束
  • Never
  • Empty
  • Throw

永不结束:没有complete状态,比如计时器,每隔1s发射item。

Never:完全不发射item,也不结束。【测试时帮助构成条件】

const interval$ = Rx.Observable.never();
//不会emit任何元素,也不会结束

interval$.subscribe(
  val=>console.log(val),
  err=>console.error('Error:' + err),
  ()=>console.log('I am complete')
);
View Code

 

Empty:流里没有元素,直接进入Complete状态。结束但不发射

const interval$ = Rx.Observable.empty(); //不会输出任何元素,直接结束

interval$.subscribe(
  val=>console.log(val),
  err=>console.error('Error:' + err),
  ()=>console.log('I am complete')
);
View Code

 

Throw:不发生任何东西,直接进入Error状态。 

const interval$ = Rx.Observable.throw('出错了');

interval$.subscribe(
  val=>console.log(val),
  err=>console.error('Error:' + err),
  ()=>console.log('I am complete')
);
View Code

 

三、工具类操作符do

一般用来做调试。

或者外部条件的设置。

流进入到下一步之前需要对外部的东西进行改变【写文件之类】

const interval$ = Rx.Observable.interval(1000)
.map(val=>val*2)
.do(v=>console.log('val is' +v))   //在map之后,take之前,在流发生之前看一下流里有什么东西
.take(3);
interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

do很像临时subscribe,但是没有把流中断掉。可以继续应用操作符。临时中间桥梁,打印值做调试。

let logLabel='当前值是';

const interval$ = Rx.Observable.interval(1000)
.map(val=>val*2)
.do(v=>{
       console.log(logLabel +v); //取得了外部的值
       logLabel='当前'; //改变了外部的值
})
.take(4);

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

 

四、变换类操作符:scan

scan:

场景:记住之前的运算结果。每次运算都会发射值。

scan接收函数作为参数,x是增加器,默认初始值0,把函数返回的结果作为下次的x。

前面序列中每发射一个值,作为y。

const interval$ = Rx.Observable.interval(1000)
.filter(val=>val%2===0)
.scan((x,y)=>{//scan接收函数作为参数
  return x+y;
})
.take(4)

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

 

五、数学类操作符reduce

数组中也有,使用比较频繁。

和scan对比,reduce只会发射一个最终值。

.filter(val=>val%2===0)
.take(4)
.reduce((x,y)=>{//reduce接收函数作为参数,只会发射一个最后的值
  return x+y;
})

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

高级用法:

const interval$ = Rx.Observable.interval(1000)
.filter(val=>val%2===0)
.take(4)
.reduce((x,y)=>{//reduce接收函数作为参数
  return [...x,y];  //每次数组加y
},[]) //x初始值为空数组[]

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

 

六、过滤类操作符 filter,take,first/last,skip...

总共100多种operator。

filter:

let logLabel='当前值是';

const interval$ = Rx.Observable.interval(1000)
.filter(val=>val%2===0)  //过滤偶数
.do(v=>{console.log(logLabel +v);
       logLabel='当前';}
)
.take(3);

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

first:

const interval$ = Rx.Observable.interval(1000)
.filter(val=>val%2===0)
.first()    //和take(1)是一样的,取第一个
// .take(1) 

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

skip: 和take相反

const interval$ = Rx.Observable.interval(1000)
.filter(val=>val%2===0)
.skip(2); //过滤掉0和2

interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
); 

用skip和take就能做到分页的效果。

七、常见创建类操作符:Interval,Timer

1、interval

const interval$ = Rx.Observable.interval(1000);
interval$.subscribe(val=>console.log(val));

通过take取前3个来看三种状态的效果

const interval$ = Rx.Observable.interval(1000).take(3);
interval$.subscribe(
  val=>console.log(val),
  err=>console.log(err),
  ()=>console.log('I am complete')
);

2、Timer

const timer$= Rx.Observable.timer(1000);

timer$.subscribe(v=>console.log(v));
//控制台只输出一个值0

第一个参数:delay多长时间

第二个参数:之后要以什么频率发送

const timer$= Rx.Observable.timer(1000,1000); //发出一个无限的递增整数序列
timer$.subscribe(v=>console.log(v));
//类似interval,但是interval不能指定开始延迟时间

 timer跟interval类似,但是可以指定delay多久开始emit。

 

实践:给Observable增加一个debug操作符

只有在生产环境才输出

import {Observable} from 'rxjs/Observable';
import {environment} from '../../environments/environment';

declare module 'rxjs/Observable' {
  interface Observable<T> {
    debug: (...any) => Observable<T>;
  }
}

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 - ');
      }
    }
  );
};

 八、自定义调试函数

在debug.util.ts中

import { pipe } from 'rxjs/index';
import { environment } from '../../environments/environment';
import { tap } from 'rxjs/internal/operators';

export const debug = (message: string) => pipe(
    tap(
        (next) => {
            if (!environment.production) {
                console.log(message, next);
            }
        },
        (err) => {
            if (!environment.production) {
                console.error('ERROR >>', message, err);
            }
        },
        () => {
            if (!environment.production) {
                console.log('Completed - ');
            }
        }
    )
);

在调用的地方通过链式管道操作符使用

getQuote(): Observable<Quote> {
        const uri = `${this.config.uri}/quotes/${Math.floor(Math.random() * 10)}`;
        return this.httpClient.get(uri).pipe(debug('quote: '), map(quote => quote as Quote))
    }

 

 

 

 

本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:https://www.cnblogs.com/starof/p/9137865.html 有问题欢迎与我讨论,共同进步。

 

posted @ 2018-06-05 08:38  starof  阅读(1491)  评论(0编辑  收藏  举报