rxjs-map相关的操作符

作者: bugWriter_y | 来源:发表于2019-05-28 22:29 被阅读24次

map

案例:获取用户输入的信息并实时进行搜索。

之前我们用subject实现过,现在我们用户fromEvent和map来实现功能

  1. html文本框

<input type="text" id="searchBox">
  1. 通过fromEvent获取用户输入事件流

import { fromEvent } from 'rxjs';
setTimeout(() => {//这里延迟1秒获取的原因是因为getElementById需要等页面渲染完毕才能获取
  var search = document.getElementById("searchBox")
  fromEvent(search, "input").subscribe(x => { console.log(x) })
}, 1000);//获取到的是事件对象
  1. 通过map操作将原来的数据事件流转换成输入文本流
import { fromEvent } from 'rxjs';
import { map } from "rxjs/operators";
setTimeout(() => {
  var search = document.getElementById("searchBox")
  fromEvent<any>(search, "input")
  .pipe(
    map(x=>x.target.value)
  )
  .subscribe(x => { console.log(x) })
}, 1000);

mergeMap

map能将发射过来的数据进行转换,一般都是从一个基本javascript对象到另一个基本javascript对象。但是有时候我们需要转换成的对象是另一个源

例如:我们我们先执行一个api查询,等上一个查询完毕后将查询出来的数据取出某个属性(比如id)再执行另一个api查询

  1. 最简单的写法
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

api1():Observable<any>{
  return this.http.get('api1')
}

api2(id:number):Observable<any>{
  return this.http.get('api1')
}
constructor(private http: HttpClient) {
  this.api1().subscribe(x => {
    console.log(x)
    this.api2(x.id).subscribe(y => {
      console.log(y)
    })
  })
}
  1. 用mergeMap实现
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { mergeMap } from "rxjs/operators";


api1(): Observable<any> {
  return this.http.get('api1')
}

api2(id: number): Observable<any> {
  return this.http.get('api1')
}
constructor(private http: HttpClient) {
  this.api1().pipe(
    mergeMap(x=>this.api2(x.id))
  ).subscribe(x=>{
    console.log(x)
  })
}

好处在哪里?如果这个是有了第三个api,需要再第二个api的基础上的话,第一种写法是继续订阅,而第二种的写法只需要再pipe中继续增加mergeMap就行了。整体代码显得更加优雅

  1. mergeMap=map()+mergeAll()。

上面的例子如果用map的话如下

this.api().pipe(
    map(x=>this.api2(x.id))
).subscribe(x=>{
    console.log(x)
})

输出出来的数据是observable对象,如果像得到具体的值,需要再跟一个mergeAll()函数,如下

this.api().pipe(
    map(x=>this.api2(x.id))
    mergeAll()
).subscribe(x=>{
    console.log(x)
})

mergeMap/concatMap/switchMap/exhaustMap

区别主要在于执行的顺序

import { interval, fromEvent } from 'rxjs';
import { mergeMap, take, concatMap, switchMap } from "rxjs/operators";

# interval(1000).pipe(take(4)) 这个是一个0,1,2,3的源,每隔一秒发射一次

# mergeMap点击后产生的[0,1,2,3]源单独发射出来,每次点击之间互不影响。如果你点击快的话,能看到一下子出来好多0的情况
fromEvent(document, "click").pipe(
  mergeMap(x => )
).subscribe(x => {
  console.log(x)
})

# concatMap和上面的不一样,每一次点击后的源都会等上一次的源所有的0,1,2,3都发射完毕了以后才发射。相当于mergeMap是并行发射的,而concatMap是串行发射的,不能交叉
fromEvent(document, "click").pipe(
  concatMap(x => interval(1000).pipe(take(4)))
).subscribe(x => {
  console.log(x)
})

# 而mergeMap干脆就是放弃之前的源。如果你上一次点击后0,1,2,3还没有发射完毕,又点击了一次,这和时候之前没有发射的数据就不发射了,之前又从0开始发射了。
fromEvent(document, "click").pipe(
  switchMap(x => interval(1000).pipe(take(4)))
).subscribe(x => {
  console.log(x)
})

# 和switchMap相反,exhaustMap是当前源的发射没有结束的话后面的源自动放弃。所以你会看到上一次的点击发射的0,1,2,3在没有结束之前你的点击都是无效的。
fromEvent(document, "click").pipe(
  exhaustMap(x => interval(1000).pipe(take(4)))
).subscribe(x => {
  console.log(x)
})

switchMap用于做搜索

因为我们的用户输入搜索条件的时候可能很频繁,而且可能还没有等到数据从后台返回就又改变了搜索条件。这个时候

  1. 为了保证数据安全,所以绝对不能用mergeMap,这个返回的数据有可能是前一个条件的数据,
  2. 也不能用concatMap,虽然它能保证最后一定是最后一次的搜索条件,但是在前一个搜索没有执行完毕之前后面的搜索可能都阻塞在这里,用户体验极差。
  3. exhaustMap也不是需要的函数,因为我们希望根据最新输入的关键词查出来数据,而不是之前输入的关键词

相关文章

网友评论

    本文标题:rxjs-map相关的操作符

    本文链接:https://www.haomeiwen.com/subject/pdfstctx.html