Angular:Rx.js

169 阅读5分钟

基本概念

  • observable 被观察对象
  • observer 观察者对象
  • pipe 对被观察对象进行处理
  • subscribe 订阅被观察对象
  • subscription 使用观察者对象订阅被观察对象生成

未命名文件 (10).jpg

// 步骤1:创建一个观察者对象
const observer = {
  next: (item: any) => console.log(item), // 步骤2:接收正常值
  error: (err: any) => console.error('error:' + err), // 步骤3:表示当有异常发生时
  complete: () => console.log('the end'), // 步骤4:表示数据接收完毕时
};
// 步骤5:创建一个被观察对象
const observable = of(3, 4, 5);
// subscription是被观察对象的执行!!!
const subscription = observable
  .pipe(
    // 步骤6:使用操作符
    filter((item) => item % 2 === 1), // 步骤7:对数据进行过滤,返回想要的数据
    map((item) => item * 3) // 步骤8:把每个源值传递给转化函数以获得相应的输出值
  )
  .subscribe(observer); // 步骤9:订阅可观察对象
subscription.unsubscribe(); // 步骤10:取消订阅可观察对象
const observable$ = Rx.Observable.fromEvent(
  document.querySelector('button'),
  'click'
);
observable$.pipe(
  throttleTime(300),
  take(3),
  map((event) => event.target.value)
);
observerable$.subscribe({
  next: (v) => {},
  error: (err) => {},
  complete: () => {},
});

Untitled.png

Rx.js创建器

  • of

of创建器的作用是将单一值转换为可观察对象类型的数据流。

import { of } from 'rxjs';
of(1, 2, 3) // 创建3个数字的数据流
.subscribe(
  next => console.log('next:', next), // 接收正常值
  err  => console.log('error:', err), // 当有异常发生时
  ()   => console.log('the end'), // 表示数据接收完毕时
);
of([1, 2, 3]) // 创建一个数组的数据流
.subscribe(item => console.log(item))
  • from

from创建器的作用是将数组转换为可观察对象类型的数据流。

import { from } from 'rxjs';

from([10, 20, 30]) // 将数组作为值的序列发出
  .subscribe(item => console.log(item)) // 输出: 10 20 30
  • range

range创建器的作用是将数字范围转换为可观察对象类型的数据流。

import { range } from 'rxjs';
range(1, 10) // 依次发出1~10
  .subscribe(item => console.log(item)) // 输出: 1 2 3 4 5 6 7 8 9 10
  • fromEvent

fromEvent创建器的作用是为DOM元素对象添加一个事件监听器,从DOM事件创建可观察对象类型的数据流。

import { fromEvent } from 'rxjs';

fromEvent(document.querySelector('button'), 'click')
  .subscribe(val => console.log(val.target)); // 输出MouseEvent对象的target属性的信息
  • timer

timer创建器的作用是创建定时器的可观察对象类型的数据流。

import { timer } from 'rxjs';

timer(3000, 1000) // 首次等待3s,然后每隔1s开始发出数据
  .subscribe(item => console.log(item)) // 3s后开始输出0,然后每隔1s,依次输出1、2、3、……
  • interval

interval创建器的作用也是创建定时器的可观察对象类型的数据流。

import { interval } from 'rxjs';

interval(1000) // 每1s依次发出0、1、2、3、……
  .subscribe(item => console.log(item)) // 1s后输出1,然后每隔1s,依次输出2、3、4、……

Subject

单播:Observable每次被订阅都创建了一个新的实例,这个实例会按照Observable里next的从头开始按部就班执行所有

多播:不论什么时候订阅只会接收到实时的数据的功能,此时就不能直接订阅Observable,而是要依靠Subject这个中间商

Untitled 1.png

  • Subject

它是一个代理对象,既是一个 Observable 又是一个 Observer,它可以同时接受 Observable 发射出的数据,也可以向订阅了它的 observer 发射数据,同时,Subject 会对内部的 observers 清单进行多播(multicast)

Untitled 2.png

import { Observable, Subject } from 'rxjs';
import { of, interval } from 'rxjs';
import { filter, map, take } from 'rxjs/operators';

// interval创建器的作用也是创建定时器的可观察对象类型的数据流
// take操作符的作用是截取数据,这里表示仅截取前3个数值。
myObservable: Observable<any> = interval(1000).pipe(take(3));
mySubject: Subject<any> = new Subject();
ngOnInit(): void {
// mySubject来订阅myObservable
  this.myObservable.subscribe(this.mySubject);
// mySubject抛出数据
  this.mySubject.subscribe((value) => console.log('A不延时' + value));
  setTimeout(() => {
    this.mySubject.subscribe((value) => console.log('B延时' + value));
  }, 1000);
}
// Observable抛出0的时候只有A订阅了,B没有订阅,所以只有A显示。过了一秒Observable抛出1此时
// A和B都已经订阅了,所以可以依次继续打印

// A不延时0秒
// A不延时1秒
// B延时1秒
// A不延时2秒
// B延时2秒
  • BehaviorSubject

BehaviorSubject是一种在有新的订阅时会额外发出最近一次发出的值的Subject

同样我们结合现实场景来进行理解,假设有我们需要使用它来维护一个状态,在它变化之后给所有重新订阅的人都能发送一个当前状态的数据,这就好比我们要实现一个计算属性,我们只关心该计算属性最终的状态,而不关心过程中变化的数,那么又该怎么处理呢?

我们知道普通的Subject只会在当前有新数据的时候发送当前的数据,而发送完毕之后就不会再发送已发送过的数据,那么这个时候我们就可以引入BehaviorSubject来进行终态维护了,因为订阅了该对象的观察者在订阅的同时能够收到该对象发送的最近一次的值,这样就能满足我们上述的需求了。

普通Subject

mySubject: Subject<any> = new Subject();
ngOnInit(): void {
  this.mySubject.subscribe((value) => console.log('A:' + value)); // 初始订阅,可以收到值
  this.mySubject.next(1);
  // A:1
  this.mySubject.next(2);
  // A:2
  this.mySubject.subscribe((value) => console.log('B:' + value)); // 无法收到值
  setTimeout(() => {
    this.mySubject.subscribe((value) => console.log('C:' + value)); // 1s后订阅,无法收到值
  }, 1000);
}
		// A:0
    // A:1
    // A:2

BehaviorSubject

这里在实例化BehaviorSubject的时候需要传入一个初始值。

// 这里在实例化BehaviorSubject的时候需要传入一个初始值。
mySubject: BehaviorSubject<any> = new BehaviorSubject(0); // 传入初始值0
ngOnInit(): void {
  this.mySubject.subscribe((value) => console.log('A:' + value)); // 全程收到值
  this.mySubject.next(1);
  // A:1
  this.mySubject.next(2);
  // A:2
  this.mySubject.subscribe((value) => console.log('B:' + value)); // 收到最后一次的值
  setTimeout(() => {
    this.mySubject.subscribe((value) => console.log('C:' + value)); // 1s后订阅,收到最后一次的值
  }, 1000);
}

		// A:0
    // A:1
    // A:2
    // B:2
    // C:2
  • ReplaySubject

ReplaySubject会保存所有值,然后回放给新的订阅者,接受参数控制重放值的数量(默认重放所有)

ReplaySubject(1) = BehaviorSubject

ReplaySubject(2) = 重放最后两次的next()

ReplaySubject( ) = 重放所有的next()

mySubject: ReplaySubject<any> = new ReplaySubject(2); // 定义取最后2次的值
ngOnInit(): void {
  this.mySubject.subscribe((value) => console.log('A:' + value)); // 全程收到值

  this.mySubject.next(0);
  this.mySubject.next(1);
  this.mySubject.next(2);

  this.mySubject.subscribe((value) => console.log('B:' + value)); // 收到最后2次的值
  setTimeout(() => {
    this.mySubject.subscribe((value) => console.log('C:' + value)); // 1s后订阅,收到最后2次的值
  }, 1000);
}
		// A:0
    // A:1
    // A:2
    // B:1
    // B:2
    // C:1
    // C:2