rxjs入门——帮你建立学习rxjs的基座

288 阅读5分钟

Rx.js绝对称得上是Angular中的一个亮点,来看看金雄同学的分享,以熟悉rxjs固定的代码结构为突破口,掌握rxjs

漫谈 rxjs 学习经历

在学会 rxjs 之前,我也是翻阅了大量的 rxjs 资料,每位作者好像都说的又对又好,但是我还是不会。直到偶尔翻到了这篇文章RxJS 快速入门,在此感谢作者。虽说前期学而不会的过程也是有用的,不是直接吃第三个馒头就能饱,但是这篇文章大大提前了我学会 rxjs 的时间。它帮我第一次认识了 rxjs,相当于一个基座,在这个基座上我开始建立自己对 rxjs 的理解。由感而发,写了这篇文章给大家分享一下。

为什么要学 rxjs

  1. 高热度,相信前端同学没有人愿意让这样的热点成为自己的盲区
  2. 项目中遇到 rxjs 代码,至少要能看懂才行
  3. rxjs 的优势:RxJS 是使用 Observables 的响应式编程的库,它使编写异步或基于回调的代码更容易。RxJS 的强大之处正是它使用纯函数来产生值的能力。这意味着你的代码更不容易出错。

rxjs 是什么

rxjs,和过去的 lodash 一样,是 js 的一个工具包。

其他有关 rxjs 是什么的说法,不要管了,都是给初学者增加上手难度的。

为你建造学习 rxjs 的基座

import { of, filter, map } from 'rxjs';

of(1, 2, 3)
  .pipe(
    filter(item => item % 2 === 1),
    map(item => item * 3)
  )
  .subscribe(item => console.log(item));

这是一段 rxjs 常见代码。

of() 称为创建器(creator),它会创建一个 Observable 类型的对象,也就是创建流。

pipe()是 Observable 对象的方法。它的包裹的 filter 和 map 称为操作符(operator),用来对数据条目进行处理。这些操作符被当作 pipe 方法的参数传进去。

subscribe()也是 Observable 对象的方法,表示消费者要订阅这个流,当流中出现数据时,传给 subscribe 方法的回调函数就会被调用,并且把这个数据传进去。这个回调函数可能被调用很多次,取决于这个流中有多少条数据。Observable 必须被 subscribe 之后才会开始生产数据。如果没人 subscribe 它,那就什么都不会做。

建议以此为基座,开始 rxjs 的学习。 为什么强调这个基座呢? 因为 rxjs 的使用,都是这种模式化的三段式的结构,也就是说使用 rxjs 时,一般都是先创建 Observable 对象,然后调用 pipe 方法(即调用各种操作符对数据流进行处理),最后用 Observable 对象的 subscribe 方法接收(订阅)处理结果。 理解了这种结构,我们就可以举一反三地掌握 rxjs 其他知识点。

1_rxjs三段式的使用模式_1677140099966.png

在基座上构建 rxjs 知识体系

2_在基座上继续扩展学习_1677140130749.png

贯穿 rxjs 的两种设计模式

  • 观察者模式

rxjs 用到了设计模式中的观察者模式。如果还不了解也不要担心,观察者模式很好理解,它有另一个名字——发布订阅模式。 我们常看的天气预报就是一个发布者,查看天气预报的各位就是订阅者。预告下雨,你看到后就会带伞。这就是一次完整的发布订阅行为,"预告"是发布者,"下雨"是数据,"你"是订阅者,"看"是订阅行为,"带伞"是你的响应。 再次回到刚才的代码, of(1, 2, 3)就是创建消息发布者,也就是创建 rxjs 中的 Observable 对象,Observable 英文原意是可观察的,和发布者意思相近。 .pipe( filter(item => item % 2 === 1), map(item => item * 3) )是数据的处理过程 .subscribe(item => console.log(item))是订阅者对消息的订阅行为,以及收到订阅消息后的响应行为。 item => console.log(item)中的 item 就是pipe管道处理后的数据,函数体console.log(item)则是响应。

  • 迭代器模式

迭代器(Iterator)模式又叫游标(Sursor)模式,迭代器具有 next 方法,可以顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表现。迭代器模式可以把迭代的过程从从业务逻辑中分离出来,迭代器将使用者和目标对象隔离开来,即使不了解对象的内部构造,也可以通过迭代器提供的方法顺序访问其每个元素。

使用 rxjs 时,会经常感觉到这是一个遍历、加工可迭代数据的工具库。

操作符

rxjs 中的操作符分为创建操作符(Creation Operator)和管道操作符(Pipeable Operator),前者用于创建 Observable 对象,后者用于处理数据流。 rxjs 5.5 版本之后,操作符都是一些独立的函数,而不是挂载在对象上。这个特点,大家可以参考一下这篇文章重学 Rxjs —— pipe 与链式调用,来进一步了解。

留一个问题:发现许多操作符的作用和 JS 原生 api 一样,那么为什么 rxjs 要重复造轮子,创建那么多内置操作符,而不是在订阅到数据后用 JS 原生 api 处理呢?

import { of } from 'rxjs';
const sumObserver = {
  sum: 0,
  next(value) {
    console.log('Adding: ' + value);
    this.sum = this.sum + value;
  },
  error() {
    // We actually could just remove this method,
    // since we do not really care about errors right now.
  },
  complete() {
    console.log('Sum equals: ' + this.sum);
  },
};
of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.
  .subscribe(sumObserver);
// Logs:
// "Adding: 1"
// "Adding: 2"
// "Adding: 3"
// "Sum equals: 6"

实战中的典型例子

import { ajax } from 'rxjs/ajax';
import { map, catchError, of } from 'rxjs';

const users = ajax({
  url: 'https://httpbin.org/delay/2',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'rxjs-custom-header': 'Rxjs',
  },
  body: {
    rxjs: 'Hello World!',
  },
}).pipe(
  map(response => console.log('response: ', response)),
  catchError(error => {
    console.log('error: ', error);
    return of(error);
  })
);

users.subscribe({
  next: value => console.log(value),
  error: err => console.log(err),
  complete: () => console.log('complete!'),
});
  • subscribe()的入参是一个 Observer 对象,这是当前官方推荐的写法。
  • next()函数的入参 value,即经过 pipe()函数处理后的一条数据。
  • error()函数用于捕获并处理错误。
  • complete()在数据流成功处理完成后执行一次,和 error()是互斥的。

Tips:rxjs 各种文档里面一般不会对 API 做详细介绍,需要了解 API 用法的话,建议直接通过代码追踪找到源码,源码里有 API 的详细讲解。

遗留问题:catchError 和 Observer 中的 error 有什么区别?