Angular 入门基础(第十篇) Rxjs 操作符的使用

126 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天。点击查看活动详情

  • RxJSReactiveX 编程理念的JavaScript 版本。ReactiveX 来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括HTTP 请求,DOM 事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。RxJS 是一种针对异步数据流编程工具,或者叫响应式扩展编程;Angular 引入RxJS 为了就是让异步可控、更简单。RxJS 里面提供了很多模块。这里我们主要给大家讲RxJS 里面最常用的ObservablefromEvent

Observable

  • 官方:表示一个概念,这个概念是一个可调用的未来值或事件的集合。
  • 通俗:数据类型可以是 number 类型,也可以是 boolean 类型,而 Observable 也是一种类型.
  • 一个 Observable 应该包含四个部分:创建、订阅、执行、清理
 const observable$ = Observable.create(observer => {//创建observable
      let i = 0;
      observer.next(i);
      setInterval(() => {
        i++;
        observer.next(i);//执行
      }, 1000);
    });
    const subscription = observable$.subscribe(value => {//订阅observable
      console.log(value) 1 2 3 4 5 6 7 8 9 10
      if (value === 10) {
        subscription.unsubscribe();//清理,即取消订阅
      }
    })

Observer

  • 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
  • 根据情况处理 Observable 发出的值.
  • 观察值可以执行值的发射,其实观察值有三种发射方式. next、 error、 complete.
  • next - 发送一个值
  • error - 发送一个错误
  • complete - 通知已完成,不再发射值
const observable$ = Observable.create((observer) => {
  let i = 0;
  observer.next(i);
  setInterval(() => {
    i++;
    if (i === 10) {
      observer.complete();
    }
    if (i === 11) {
      //不会执行,因为在第10秒已经执行了complete
      observer.error("finish");
    }
    observer.next(i);
  }, 1000);
});
const _observer = {
  next: (value) => console.log("收到一个值:" + value),
  error: (err) => console.log("收到一个错误:" + err),
  complete: () => console.log("已完成计时!"),
};
observable$.subscribe(_observer);

Subscription

  • 表示 Observable 的执行,主要用于取消 Observable 的执行。
  • 当你使用 subscribe()时,返回一个 Subscription 对象,该对象有一个 unsubscribe() 方法.

在 RxJS 中用来解决异步事件管理的的基本概念是:

  • Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。
  • Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
  • Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
  • Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
  • Subject : 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
  • Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。

Subject

Subject 是一种特殊类型的 Observable,它允许将值多播给多个观察者,所以 Subject 是多播的, 而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。 每个 Subject 都是观察者。 - Subject 是一个有如下方法的对象: next(v)、error(e) 和 complete() 要给 Subject 提供新值,只要调用 next(theValue),它会将值多播给已注册监听该 Subject 的观察者们。

     import { Subject, from } from 'rxjs';
    const subject = new Subject<number>();

    subject.subscribe({
      next: (v) => console.log(`observerA: ${v}`)
    });
    subject.subscribe({
      next: (v) => console.log(`observerB: ${v}`)
    });

    subject.next(1);
    subject.next(2);

// Logs:
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2

因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法

import { Subject, from } from 'rxjs';

const subject = new Subject<number>();

subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`)
});
subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`)
});

const observable = from([1, 2, 3]);

observable.subscribe(subject);

// Logs:
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2
// observerA: 3
// observerB: 3

Operators (操作符)

采用函数式编程风格的纯函数 (pure function),使用像 map 、 filter 、 concat 、 flatMap 等这样的操作符来处理集合。

操作符就是 Observable 提供的方法.当你调用操作符时,Observable 并不会改变, 而且操作符会返回一个全新的 Observable.我们再次改造计时器的案例, 这次不再使用这么原始的方式,而是使用操作符来完成 Observable 的创建、延时等操作

const observable$ = timer(0, 1000).pipe(take(11));
observable$.subscribe(console.log);

timer:第一个参数是延时执行时间,第二个参数是间隔执行时间.自身会返回一个

Observable.timer(0,1000)是指延时 0 秒执行,每隔 1 秒发出一个值.他会从 0 开始发送,无限递增

pipe:管道,可以对一些操作符进行链式调用

take:指执行的次数. take(11)则只发送前 11 个值

Rxjs 异步数据流编

  • 目前常见的异步编程的几种方法:
  • 1)、回调函数
  • 2)、事件监听/发布订阅
  • 3)、Promise
  • 4)、Rxjs

PromiseRxJS 处理异步对比

Promise 处理异步:

let promise = new Promise((resolve) => {
  setTimeout(() => {
    resolve("---promise timeout---");
  }, 2000);
});
promise.then((value) => console.log(value));

RxJS 处理异步:

import { Observable } from "rxjs";
let stream = new Observable((observer) => {
  setTimeout(() => {
    observer.next("observable timeout");
  }, 2000);
});
stream.subscribe((value) => console.log(value));

从上面列子可以看到RxJSPromise 的基本用法非常类似,除了一些关键词不同。Promise里面用的是then()resolve(),而RxJS 里面用的是next()subscribe()

PromiseRxJS 的用法基本相似。其实Rxjs 相比Promise 要强大很多。比如``Rxjs中可以中途撤回、Rxjs可以发射多个值、Rxjs` 提供了多种工具函数等等。

Rxjs 订阅后多次执行

  • 如果我们想让异步里面的方法多次执行,比如下面代码。
  • 这一点Promise 是做不到的,对于Promise来说,最终结果要么resole(兑现)、要么reject(拒绝),而且都只能触发一次。如果在同一个Promise对象上多次调用resolve 方法,则会抛异常。而Observable 不一样,它可以不断地触发下一个值,就像next() 这个方法的名字所暗示的那样。
let promise = new Promise((resolve) => {
  setInterval(() => {
    resolve("---promise setInterval---");
  }, 2000);
});
promise.then((value) => console.log(value));

Rxjs

let stream = new Observable<number>((observer) => {
  let count = 0;
  setInterval(() => {
    observer.next(count++);
  }, 1000);
});
stream.subscribe((value) => console.log("Observable>" + value));

Rxjs 延迟执行

dom转换成dom流,然后对整个dom流进行处理

import { Observable, fromEvent } from "rxjs";
import { map, filter, throttleTime } from "rxjs/operators";
var button = document.querySelector("button");
fromEvent(button, "click")
  .pipe(throttleTime(1000))
  .subscribe(() => console.log(`Clicked`));

catchError

// 发出错误
const source = throwError("This is an error!");
// 优雅地处理错误,并返回带有错误信息的 observable
const example = source.pipe(catchError((val) => of(`I caught: ${val}`)));
// 输出: 'I caught: This is an error'
const subscribe = example.subscribe((val) => console.log(val));

throwError

const result = concat(of(7), throwError("error"));
result.subscribe(
  (x) => console.log(x),
  (e) => console.error(e)
);