Rxjs 响应式编程和异步编程(一)

javascript/jquery

浏览数:100

2020-7-16

AD:资源代下载服务

在Angular中,内置了很多可观察(Observable)对象,这些对象具有可订阅性,当有消费者调用subscribe()方法时,这个函数就执行,普遍用于前端请求处理的场景。本篇暂时脱离Angular,集中到rxjs本身的api操作符上,挑选最常见的操作符作为demo。

操作符

按照类型划分为 组合条件创建错误处理过滤多播转换工具

创建一个 Observable

create

import { Observable,from } from 'rxjs';
const content = Observable.create((observer)=>{
    observer.next('something');
});

from

import { Observable,from } from 'rxjs';
const source = from([1,2,3,4]);

fromEvent 将事件转成 Observable 序列

import { fromEvent } from 'rxjs';
const source = fromEvent(document, 'click');
source.subscribe(val => {
    console.log(val);
})

of 按顺序发出任意数量的值

import { of } from 'rxjs';
const source = of(1,2,3,4);

其他:
empty 立即完成

const subscribe = empty().subscribe({
  next:()=>console.log('next'),
  complete:()=>console.log('complete')
});

interval 基于给定时间间隔发出数字序列

source.subscribe(res=>{
  console.log(res);
});

timer 给定一定的时间后,根据第二参数时间间隔发出值,缺失第二参数,则只发出一次值

const source = timer(1000,500);
source.subscribe(res=>{
  console.log(res);
});

过滤操作

filter 类似数组的操作api,挑选符合条件的进行返回
比如从一组返回的数据中筛选符合的样本,原本的做法是订阅者将数据全部获取进行筛选,这份工作可以转移到filter操作中进行,订阅者拿到的就是符合预期的数据。

const source = from([1, 2, 3, 4, 5, 6]).pipe(filter((o: number) => o > 3));
source.subscribe(res=>{
  console.log(res);
});

take 在完成前指定发出N个值
如:首次点击有效

const oneClickEvent = fromEvent(document, 'click')
  .pipe(
    take(1)
  );
oneClickEvent.subscribe(event => {
  console.log(event);
});

转换(核心)

map 对每个源observable的每个值应用投射函数(加工处理,格式转换、补全等)

const source = from(['abc', 'DEf', 'cDt']).pipe(
  map((o: any) =>
    o.toLocaleLowerCase()
  )
);
source.subscribe(res=>{
  console.log(res);
});

switchMap和其他打平操作符的主要区别是它具有取消效果。在每次发出时,会取消前一个内部 observable (你所提供函数的结果) 的订阅,然后订阅一个新的 observable 。你可以通过短语切换成一个新的 observable来记忆它。
应用:拦截后处理,取消之前发出但还未结束的订阅操作。
模拟两个按钮发起可订阅的操作(如http请求)

const mapBtn = window.document.getElementsByClassName('btn');
const switchMapBtn = window.document.getElementsByClassName('switchMap');
const interval$ = interval(1000);
let mapClickCount = 0;
let switchMapCount = 0;
const source = fromEvent(mapBtn, 'click')
  .pipe(
    map(event => {
      mapClickCount++;
      return interval$;
    }),
  );
source.subscribe((observal) => {
  observal.subscribe(res => {
    console.log(`map clickCounts: ${mapClickCount},and res is ${res}`);
  })
});
const switchMapSource = fromEvent(switchMapBtn, 'click')
  .pipe(
    switchMap(event => {
      switchMapCount++;
      return interval$;
    }),
  );
switchMapSource.subscribe(res => {
  console.log(`switchMap clickCounts: ${switchMapCount},and res is ${res}`);
})

点击第一个普通订阅按钮2次(间隔1s):

对比使用switchMap的按钮:

图2中每次按钮点击都会取消之前的订阅数值,重新计算。

工具

toPromise 将 obeservable转换成promise。

const source = from([1, 2, 3]);
const promise: Promise<any>[] = [];
source.pipe(
  map(o => {
    return of(o).toPromise()
  })
).subscribe(res => {
  promise.push(res);
});
Promise.all(promise).then(res=>{
  console.log(res); //[1,2,3]
});

delay 延迟时间

const source = from([1, 2, 3]);
source.pipe(
  map(o => {
    console.log(new Date().getSeconds());
    return o;
  }),
  delay(5000)
).subscribe(res=>{
  console.log(`${new Date().getSeconds()} ${res}`);
});

tap 5.5v以前的do操作符重命名,使用场景:输出执行日志等

const source = from([1, 2, 3]);
source.pipe(
  tap(o => console.log(o)),
  map(o => {
    return o;
  }),
).subscribe(res => {
  console.log(`${res}`);
});

Rxjs学习网址:https://cn.rx.js.org/class/es6/Observable.js~Observable.html
翻译网站:
https://rxjs-cn.github.io/learn-rxjs-operators/

作者:何弃疗