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') );
Empty:流里没有元素,直接进入Complete状态。结束但不发射
const interval$ = Rx.Observable.empty(); //不会输出任何元素,直接结束 interval$.subscribe( val=>console.log(val), err=>console.error('Error:' + err), ()=>console.log('I am complete') );
Throw:不发生任何东西,直接进入Error状态。
const interval$ = Rx.Observable.throw('出错了'); interval$.subscribe( val=>console.log(val), err=>console.error('Error:' + err), ()=>console.log('I am complete') );
三、工具类操作符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 有问题欢迎与我讨论,共同进步。
如果觉得本文对您有帮助~可以
微信支持一下: