【rx】rx汇总总结
rx学习指南
https://rxjs-cn.github.io/learn-rxjs-operators/
https://robin-front.gitbooks.io/rxjs-doc-chinese/
https://segmentfault.com/a/1190000019753692 缓存
https://segmentfault.com/a/1190000007562818
https://zhuanlan.zhihu.com/p/146007671 返回按钮
https://limeii.github.io/2019/08/rxjs-unsubscribe/ 退订理解
https://www.dazhuanlan.com/2019/12/10/5deed365a3c52/
1、map
map和javascript中的数组的map方法类似
const getData = (param) => { return of(`return: ${param}`).pipe( delay(Math.random() * 1000) ) }; from([1, 2, 3, 4,5]) .pipe( map(param => getData(param)), ) .subscribe(val => console.log(val));
返回的是6 observable
2、concatAll
javascript中数组也有一个方法叫做concat,concatAll有个flatten效果
from([1, 2, 3, 4, 5]) .pipe( map(param => getData(param)), concatAll() // 比上个例子多出的部分 ) .subscribe(val => console.log(val));
return: 1 return: 2 return: 3 return: 4 return: 5
3、concatMap
map和concatAll直接结合成一个操作符
from([1,2,3,4,5]) .pipe( concatMap(param => getData(param)) ) .subscribe(val => console.log(val));
4、mergeAll
from([1, 2, 3, 4, 5]) .pipe( map( item => getData(item) ), mergeAll() ) .subscribe(v => console.log(v));
随机 也可以实现concatAll的效果,只要 mergeAll(1) 就可以了
5、mergeMap(又叫flatMap)
from([1, 2, 3, 4,5]) .pipe( mergeMap(param => getData(param)) ) .subscribe(val => console.log(val));
6、switchAll
from([1,2,3,4,5]).pipe( map(param => getData(param)), switchAll() ).subscribe(val => console.log(val));
return 5
map之后产生的五个observable, 经过switchAll之后,由于五个observable的delay不同,所以还没来得及发射数据,就被最后的observable给‘踢’掉了
7、switchMap
map之后switchAll也可以合并成一个操作
会在新的 Observable 对象发出新值后 退订前一个未处理完的 Observable 对象
from([1,2,3,4,5]) .pipe( switchMap(param => getData(param)) ) .subscribe(val => console.log(val));
8、forkJoin
forkJoin 是 Rx 版本的 Promise.all()
,即表示等到所有的 Observable 都完成后,才一次性返回值
const getPostOne$ = Rx.Observable.timer(1000).mapTo({id: 1}); const getPostTwo$ = Rx.Observable.timer(2000).mapTo({id: 2}); Rx.Observable.forkJoin(getPostOne$, getPostTwo$).subscribe( res => console.log(res) // [{id: 1}, {id: 2}] );
9、处理两个请求
1、当我们发送下一个请求时,需要依赖于上一个请求的数据。即我们在需要在上一个请求的回调函数中获取相应数据,然后在发起另一个 HTTP 请求
import { Component, OnInit } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; @Component({ selector: 'app-root', template: ` <p>{{username}} Detail Info</p> {{user | json}} ` }) export class AppComponent implements OnInit { constructor(private http: Http) { } apiUrl = 'https://jsonplaceholder.typicode.com/users'; username: string = ''; user: any; ngOnInit() { this.http.get(this.apiUrl) .map(res => res.json()) .subscribe(users => { let username = users[6].username; this.http.get(`${this.apiUrl}?username=${username}`) .map(res => res.json()) .subscribe( user => { this.username = username; this.user = user; }); }); } }
先从 https://jsonplaceholder.typicode.com/users
地址获取所有用户的信息,然后再根据指定用户的 username
进一步获取用户的详细信息
import { Component, OnInit } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/mergeMap'; @Component({ selector: 'app-root', template: ` <p>{{username}} Detail Info</p> {{user | json}} ` }) export class AppComponent implements OnInit { constructor(private http: Http) { } apiUrl = 'https://jsonplaceholder.typicode.com/users'; username: string = ''; user: any; ngOnInit() { this.http.get(this.apiUrl) .map(res => res.json()) .mergeMap(users => { this.username = users[6].username; return this.http.get(`${this.apiUrl}?username=${this.username}`) .map(res => res.json()) }) .subscribe(user => this.user = user); } }
通过 mergeMap
操作符,解决了嵌套订阅的问题
10、Promise的链式调用 很好解决并行和串行请求,但是Promise本身是无法取消的
https://blog.csdn.net/rj0024/article/details/89207201?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1
存在问题:
在单页面应用中,resolve回调里需要进行try/catch处理,特别是在回调里有DOM操作的时候。否则,在接口响应慢的时候进行路由切换会导致控制台报错,甚至导致页面陷入无法交互的境地
由于接口响应慢而导致的竞态条件问题
rxjs是可以取消的,对于Promise出现的两个问题
在切换路由,组件销毁时调用unsubscribe方法取消订阅,回调里的逻辑便不会执行
竞态条件是由于接口异步调用的回调顺序不可控导致的,rxjs的switchMap操作符可以确保每次接收到的都是最新一次发送的值(即最新的接口回调的值)
11、distinct(lambda) distinctUntilChanged([(Prev, current)=>{}]) 和 distinctUntilKeyChanged(key)
过滤掉重复的项
from([1, 2, 2, 3, 2]) .pipe(distinct()) .subscribe(l); // 1,2,3
12、debounce(lambda: Observable) 和 debounceTime(number)
延时发送源发出的值, 如果期间源发出了新值的话,返回的值为最新的值,上一个会被丢弃掉(避免高消费事件时使用)
13、find 和 findIndex
类似 Array.prototype.find()
14、toPromise
把 Observable 转化为 promise
click = async e => { let res = await ajax('http://localhost:1995/a').pipe(map(res => res.response)).toPromise(); l(res) }
15、buffer bufferCount bufferTime bufferToggle bufferWhen
buffer系列,将过去的值作为数组收集,在事件触发时发出收集好的值
const send$= fromEvent(document, 'click'); const interval = interval(1000); const buffered = interval.pipe(buffer(send$)); buffered.subscribe(l);
16、delay delayWhen
延迟来自源Observable的项目的发射
17、endWith
from([1, 2]) .pipe(endWith("源观察完成后,附加一个发射,然后完成。")) .subscribe(l); // 1, 2, "源观察完成后,附加一个发射,然后完成。"
18、onErrorResumeNext
当任何提供的 Observable 发出完成或错误通知时,它会立即地订阅已传入下一个 Observable
Rx.Observable.of(1, 2, 3, 0) .map(x => { if (x === 0) { throw Error(); } return 10 / x; }) .onErrorResumeNext(Rx.Observable.of(1, 2, 3)) .subscribe( val => console.log(val), err => console.log(err), // 永远不会调用 () => console.log('that\'s it!') ); // 输出: // 10 // 5 // 3.3333333333333335 // 1 // 2 // 3 // "that's it!"
19、Rxjs的pipe怎么像Promise的then一样等待ajax结束才继续?
from(this.getOne) .pipe( mergeMap(oneData => { console.log(oneData) return from(this.getTwo) }), mergeMap(twoData => { console.log(twoData) return from(this.getThree) }) ) .subscribe(threeData => { console.log(threeData) ... })
20、pipe
Pipe是RxJs的一个特性。根据角度文件
Pipe允许您将多个函数组合成一个函数。函数的参数是要组合的函数,并返回一个新函数,该函数在执行时按顺序运行组合的函数
import { filter, map } from 'rxjs/operators'; const squareOdd = of(1, 2, 3, 4, 5) .pipe( filter(n => n % 2 !== 0), map(n => n * n) );// Subscribe to get values squareOdd.subscribe(x => console.log(x));
21、do
this.searchService.windowScroll() .do(() => this.isLoading = true) .map((page) => this.searchService.query(page)) .switch() .subscribe((res) => { this.results = [...this.results, ...res.data] this.isLoading = false })
22、
// 间隔 1s 请求 this.timer$ = interval(1000) .pipe( // 取消过时的请求值 switchMap(() => { return this.http.get(API); }), ) .subscribe( (res: any) => { // 百分数处理逻辑 }, () => { this.timer$.unsubscribe(); }, () => { this.timer$.unsubscribe(); }, );
23、搜索
let input = document.querySelector('#input'); //return some ajax data let ajaxSearch = function (input) { //mock data return Promise.resolve(`search data: ${input}`); }; let source = Rx.Observable.fromEvent(input, 'keyup'); source .map(event => event.target.value) .debounce(500) .distinctUntilChanged() .filter(input => { input = input.replace(/\s+/, ""); return input !== ''; }) .flatMapLatest(ajaxSearch) .subscribe(log);
首先将 Input 的 keyup 作为事件源
使用 map 获得输入的值
使用 debounce 去抖,即500ms获取一个值,防止频繁发送请求
使用 distinctUntilChanged 去掉重复的值,防止搜索重复的内容
使用 filter 滤除空字符串
使用 flatMapLatest 获取请求中的内容,flatMapLatest 用法与 flatMap 类似,但是如果上一次的请求还未返回,又发出一个新请求,则忽略上一个请求
24、Promise 转化为 Observalble
// 数组(Iterables, 也可以是 Map Set Generators)作为数据流 var source = Rx.Observable.from([1,2,3]); // Promise 转化为 Observalble let promise = Promise.resolve(0); let source = Rx.Observable.fromPromise(promise); //从callback转化 let callback=(i,fn)=>fn(i+1); let addOne = Rx.Observable.fromCallback(callback); addOne(0).subscribe(log); // => 1
25、网络实例代码
reloadUsers(): void { console.log('reload users'); this.users$ = this.route.paramMap.pipe( switchMap((params: ParamMap) => { return this.serverUserService.findByServerId(params.get('serverId')); }) ); } deleteUser(serverUserId: string): void { this.serverUserService.deleteUser(serverUserId).subscribe({ next: response => { if (response.success) { this.messageService.success('服务器用户删除成功!'); debugger; this.users$ = this.users$.pipe( switchMap(users => { return of(users.filter(user => { return user.serverUserId != serverUserId; })); }) ); } else { this.messageService.error(response.message); } } }) }
import {Observable, from} from 'rxjs' // 新建⼀个可订阅对象 let obser = new Observable<string>(productor => { // ⾃定义数据流 productor.next("hello") productor.next("world") setTimeout(()=>{ productor.next("After 1 Sec") productor.complete() }, 1000) }) // 消费 obse.subscribe({ next(item) { console.log(item) }, error(err) { console.log(err) }, complete() { console.log("Done") } }
public post<T>( destination: string, data?: any, options: RequestOptions = {} ): Observable<AxiosResponse<T>> { this.unsubscribe = new Subject<any>(); return new Observable<AxiosResponse<T>>((observer: any) => { this.processCustomParameters(options); axios .post(destination, data, options as AxiosRequestConfig) .then((response: AxiosResponse<T>) => { observer.next(response); observer.complete(); }) .catch((error: any) => { observer.error(HttpClient.converterErrorResponse(error)); }); }).pipe(takeUntil(this.unsubscribe)); }
26、rsjs5
var subject = new Rx.BehaviorSubject(56); subject.onCompleted(); var subscription = source.subscribe( function (x) { console.log('Next: ' + x); }, function (err) { console.log('Error: ' + err); }, function () { console.log('Completed'); }); // => Next: 56 subject.onNext(42); // => Next: 42 subject.onCompleted(); // => Completed