RxJS入门分享

2022-07-11  本文已影响0人  pengji

RxJS 实战(入门)分享

Reactive Extensions Library for JavaScript
  1. 📙 什么是RxJS?

Think of RxJS as Lodash for events.

  1. RxJS 是为响应式编程设计的库,它利用 Observables 模式方便我们编写基于异步组合或者回调的代码)

  2. Rx (Reactive extensions) 利用迭代器和观察者模式(观察者模式迭代器模式 ),函数式编程(函数式编程)来优雅的编写和管理事件序列代码的编程思想。

大脑 🧠: 懂了,又没完全懂

Tips: 观察者模式 & 迭代器模式

  1. 观察者模式

  2. 释义:将逻辑分成发布者和观察者。

  3. 发布者:负责产生事件,它会通知所有的注册挂号的观察者。不关心观察者如何处理事件。

  4. 观察者:只负责接收事件并处理自身逻辑,不关心事件如何产生。

  5. 图解:

  1. 迭代器模式

  2. 释义:指的是一个可遍历的对象数据集合的实现。方式有很多,比如数组、链表、树等等迭代器的作用是就是提供一个统一的遍历接口,不需要使用者关心内部的数据集合的实现方式。

  3. 图解:

Tips2:编程范式 - 响应式编程 & 函数式编程

编程范式

听到了听到了,两只耳朵都听到了,赶快给我说说RxJS

  1. 🌰 看个栗子

问1: 页面输入框中,如何过滤掉小于3个字符长度的目标值?

/**
 * 常规命令式实现
 */

const input2$ = document.querySelector('.input2');
input2$.addEventListener('input', (event: Event) => {
  const res = (event.target as HTMLInputElement).value;
  if (res.length > 2) {
    console.log(res);
  }
});

import { fromEvent } from 'rxjs';
import { filter, map } from 'rxjs/operators';

/**
 * rxjs 实现
 */

const input$ = fromEvent(document.querySelector('.input1'), 'input');

input$
  .pipe(
    filter(
      (event: InputEvent) => (event.target as HTMLInputElement).value.length > 2
    ),
    map((event: InputEvent) => (event.target as HTMLInputElement).value)
  )
  .subscribe((value: string) => console.log(value));

看起来没有太多优势? 从代码量上来讲,还有可能劣化了?

问2: 上面的输入框每次输入之后都动态保存到后端,如何实现?

/**
 * 常规命令式实现
 */

// 防抖 自己实现 or lodash 之类的方法库
function debounce(fn, delay = 500) {
  let timer = null;

  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
    }, delay);
  };
}

const input2$ = document.querySelector('.input2');
// 同步
input2$.addEventListener('input', debounce(async (event: Event) => {
    const res = (event.target as HTMLInputElement).value;
    if (res.length > 2) {
      // 异步, 保存数据
      await saveData();
    }
}, 600));

import { fromEvent } from 'rxjs';
import { filter, map, debounceTime, tap } from 'rxjs/operators';

/**
 * rxjs 实现
 */

const input$ = fromEvent(document.querySelector('.input1'), 'input');

input$
  .pipe(
    filter(
      (event: InputEvent) => (event.target as HTMLInputElement).value.length > 2
    ),
    map((event: InputEvent) => (event.target as HTMLInputElement).value),
    debounceTime(600),
    tap(saveData)
  )
  .subscribe();

在线代码: https://stackblitz.com/edit/rxjs-u1sphw?file=index.ts

  1. 🙋 解决什么问题?

使用响应式编程来解决同步/异步混用问题。

最大目的是提供一系列抽象的操作符可以对数据进行转换,而不管这些数据来源是同步或异步的。

理解点1:流(streams)

流(streams): 随时间流逝的一系列事件。

举个例子:

image.png

流的概念具体在 rxjs 里面,就是 Observerable 和 Observer 的关系, 如下图所示

image.png
// 创建一个流
// RxJS v6+
import { Observable } from 'rxjs';
/*
  创建在订阅函数中发出 'Hello' 和 'World' 的 observable 。
*/
const hello = new Observable(function(observer) {
  observer.next('Hello');
  observer.next('World');
});

// 输出: 'Hello'...'World'
const subscribe = hello.subscribe(val => console.log(val));

https://stackblitz.com/edit/typescript-baxh98?file=index.ts&devtoolsheight=100

理解点2: Observable & observer & Subscription

  1. 定义

import { Observable } from 'rxjs';

const node = document.querySelector('input');
// input$ 可观察对象 Observable
const input$ = Observable.fromEvent(node, 'input');

/**
* 以下的对象为完整的observer
*   {
    next: (event) => console.log(`You just typed ${event.target.value}!`),
    error: (err) => console.log(`Oops... ${err}`),
    complete: () => console.log(`Complete!`)
    }
*  也可以使用 .subscribe(console) 来简写next的输入  
*/
const subscription = input$.subscribe({
  next: (event) => console.log(`You just typed ${event.target.value}!`),
  error: (err) => console.log(`Oops... ${err}`),
  complete: () => console.log(`Complete!`)
});

// 取消监听
subscription.unsubscribe();
  1. 与Promise对比

由于 Observable 的创建方式和 Promise 有点像,因为用他们做对比学习可能效果更好。

image.png

promise 是一次性的,在异步任务执行完毕后,promise 就被标记为 fullfilled 或者 rejected 状态。

Observable 不是一次性的,在异步任务中可以通过 next 多次触发。只有收到 error 或者 complete,订阅才会结束。

当创建事件发送的逻辑时,所有的逻辑是在订阅后才执行。

import { Observable } from "rxjs";

//创建 promise
const promise = new Promise(resolve => {
  console.log("run promise");
  setTimeout(() => resolve("ok"), 2000);
});

//订阅promise
// promise.then(console.log);

//创建 observable
const observable = new Observable(subscriber => {
  console.log("run observable");
  setTimeout(() => {
    subscriber.next("ok");
    subscriber.complete();
  }, 2000);
});

// observable.subscribe(console.log);

promise是只为单个值设计的,所以当收到一个值之后这个 promise 就结束了。但是 observable不是,只要没有 complete 或者出现 error,它可以发送多个值。

import { Observable } from "rxjs";

//创建 observable
const observable = new Observable(subscriber => {
  let count = 0;
  const id = setInterval(() => {
    subscriber.next(++count);
  }, 1000);

  return () => {
    clearInterval(id);
  };
});

//每间一秒加一
const sub = observable.subscribe(console.log);
//两秒后取消监听,导致事件停止发送
setTimeout(() => sub.unsubscribe(), 2000);

Promise 和 Observable的对比


image.png

理解点3: 操作符 🔗

image.png image.png image.png image.png image.png image.png image.png image.png image.png
  1. 🍽️ 试着做点什么

  2. rxjs 在angular & nestjs 中的应用

nestjs 在源码中大量使用RxJS, 通过流的方式来管理组件间以来的关系。

image.png
  1. axios 重试 https://juejin.cn/post/6933033465126322184

  2. 富交互操作

  3. 游戏

  4. 在线体验:http://acfun-share-demo.web-ops.staging.kuaishou.com/

  5. https://git.corp.kuaishou.com/acfun-frontend/acfun-share-demo/-/tree/master/rxjs

image.png
  1. 埋点

  2. 低码

  3. 😅 最后说点啥

思考:

RxJS被很多人奉为开发中的银弹或者屠龙技,那为什么RxJS没有像 lodash、vue、react等js库一样被广泛传播并且使用呢?

image.png
  1. ✨ 参考书籍 & 资料:

上一篇下一篇

猜你喜欢

热点阅读