【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

 


 



posted @ 2020-07-11 08:19  五艺  阅读(406)  评论(0编辑  收藏  举报