RxJS入门概念理解

概述

RxJS 是一个使用可观察序列编写异步和基于事件的程序的库。它提供了一种核心类型,即 Observable、一些周边类型(Observer、Scheduler、Subjects)和类似于 Array 方法(mapfilterreduceevery 等)的操作符,以便将异步事件作为集合进行处理。

可以将 RxJS 视为处理事件的 Lodash。

RxJS 中解决异步事件管理的基本概念有:

  • Observable(可观察者) 表示未来(future)值或事件的可调用集合的概念。
  • Observer(观察者) 是一个回调集合,它知道如何监听 Observable 传来的值。
  • Subscription(订阅) 表示 Observable 的一次执行,主要用于取消执行。
  • Operator(操作符) 是纯函数,可以使用 mapfilterconcatreduce 等操作来以函数式编程风格处理集合。
  • Subject(主体: 相当于一个 EventEmitter,也是将一个值或事件多播到多个 Observers 的唯一方式。
  • Scheduler(调度器) 是控制并发的集中化调度器,允许我们在计算发生时进行协调,例如 setTimeoutrequestAnimationFrame 或其它。

让我们用简单的代码理解一下上面的概念

Observable-Observer-Subscription关系

js 复制代码
const { fromEvent, filter } from 'rxjs'

const click$ = fromEvent(document, 'click')  // 从文档的点击事件创建了Observable,即可观察者

const observer = { next: (event) => console.log(event) } // 创建Observer, 即观察者,包含一个 `next` 方法用于记录事件

const subs = click$  // 建立订阅对象,并传入观察者对象
            .pipe(filter((e) => e.clientY > 100)) // filter操作符,当返回结果为false时,不会触发后面的订阅函数
            .subscribe(observer); // 必须
    
subs.unsubscribe(); // 取消订阅

通俗一点讲就是,我们要观察document的点击事件(Observable),观察到了,我们就触发log方法(observer),但是我们只有通过pipe(管道)连接两者,并订阅(Subscription),才会通知到Observer。

用个例子,我要你去偷听一个人打电话然后告诉我,打电话就是可观察者(Observable),你就是观察者(Observer)观察到了之后干啥呢,告诉我(next事件),我要你去偷听是订阅(Subscription),如果没有订阅,你不会去听。中间你对我叙述听到的内容,你可以简短了说,也可以添油加醋的说,这就是中的操作符,你怎么操作的我不管,反正我听到的是你告诉我的内容。

说一下主体Subject

js 复制代码
const { fromEvent, filter, Subject, take } from 'rxjs'
 
const subject = new Subject(); // 创建主体对象,之后主要靠主体对象来进行广播

const click$ = fromEvent(document.getElementsByTagName('h1'), 'click');

// take是设定事件只触发两次,后面是将click$全部交给subject主体进行广播
click$.pipe(take(2)).subscribe(subject);

// 最后在有subject去建立Observe连接
const subs1 = subject.subscribe((e) => console.log(1));
const subs2 = subject.subscribe((e) => console.log(2));

    
subs1.unsubscribe(); // 取消订阅
subs2.unsubscribe(); // 取消订阅

广播顾名思义,就是一对多。 用上面的例子理解就是:subject理解为一个中介,我让你去听电话,他让你去看别人在干嘛,我们不直接对发号施令,而是通过中介。

调度器Schedule

在RxJS中,Schedulers(调度器)是用于控制 Observable 执行时的执行上下文(例如同步或异步)的一种机制。调度器允许你明确地定义 Observable 在何时、何地以及如何执行其操作。

简单说就是用来控制事件发出的顺序和速度的(发送给观察者的)。它还可以控制订阅 ( Subscriptions ) 的顺序。

RxJS 提供了几个内置的调度器,其中常见的包括:

  1. queueScheduler(队列调度器):

    使用 queueScheduler 时,操作会被放入一个队列,并在事件循环的下一个时刻执行。这是默认的调度器。

js 复制代码
const observable = from([1, 2, 3]); 

observable.pipe( 
     observeOn(queueScheduler)) // 使用队列调度器
    .subscribe(value => console.log(value));

使用 queueScheduler,操作会按顺序被放入队列,然后在下一个事件循环中执行。

  1. asapScheduler(asap 调度器):

    使用 asapScheduler 时,操作会在当前任务队列结束时(在当前宏任务结束前)尽快执行,这比 queueScheduler 更快。

js 复制代码
    import { asapScheduler, asyncScheduler, from } from 'rxjs';
    function syncSchedulerMain() {
        console.log('before');
        from([1, 2, 3]).subscribe(console.log)
        console.log('after');
    }
    syncSchedulerMain();
    // 执行结果:
    // before
    // 1
    // 2
    // 3
    // after

使用 asapScheduler,操作会在当前任务队列结束时(在当前宏任务结束前)尽快执行。

  1. asyncScheduler(异步调度器):

    使用 asyncScheduler 时,操作会被安排在一个微任务队列中,在当前任务执行完成后立即执行。这比 asapScheduler 更快。

js 复制代码
    function asyncSchedulerMain() {
        console.log('asyncScheduler: before');
        from([1, 2], asyncScheduler).subscribe(console.log)
        Promise.resolve('asyncScheduler: promise').then(console.log);
        console.log('asyncScheduler: after');
    }
    // 执行结果:
    // asapScheduler: before
    // asapScheduler: after
    // 1
    // 2
        // asapScheduler: promise

使用 asyncScheduler,操作会在微任务队列中被安排,在当前任务执行完成后立即执行。

  1. animationFrameScheduler(动画帧调度器):

    使用 animationFrameScheduler 时,操作会在浏览器的下一个动画帧中执行,通常用于与动画相关的场景。

调度器可以通过在 Observable 上使用 observeOn 操作符来指定

js 复制代码
const observable = from([1, 2, 3]); 

observable.pipe( 
     observeOn(animationFrameScheduler)) // 使用动画帧调度器
    .subscribe(value => console.log(value));

使用 animationFrameScheduler,操作会在浏览器的下一个动画帧中执行,通常用于与动画相关的场景。

RxJS相关辅助链接

  1. RxJS官网
  2. Rx Visualizer
  3. Rxjs动画演示对比
  4. 弹珠图
  5. RxJS在线编辑器
相关推荐
泯泷34 分钟前
手搓JSVM第 12 篇:完整最小 JSVM 实现与源码设计复盘
前端·javascript·前端框架
默_笙1 小时前
🍔 给 AI 发一张结构化表格(下):从"自由发挥"到"按格填空"的输出驯服指南
前端·javascript
泯泷1 小时前
手搓JSVM第 11 篇:打包、模块与 CLI:把 VM 产物变成可运行文件
前端·javascript·前端框架
泯泷1 小时前
手搓JSVM第 10 篇:对象、数组与属性访问
前端·javascript·前端框架
泯泷1 小时前
手搓JSVM第 9 篇:闭包:函数如何记住外部变量
前端·javascript·前端框架
晴天162 小时前
前端 SSR、BFF 原理介绍
前端·javascript·网络·html
全栈技术负责人2 小时前
AI 效能工具建设:Agent 可观测性技能技术方案与实践
前端·ai·ai编程
梦想平凡2 小时前
百游棋牌源代码开发搭建教程(一):全端工程结构、开发环境配置与首次启动验证
前端·javascript·源代码管理
妙码生花3 小时前
两个月 59 篇 AI 开发日志 + Golang 商业级实战项目收工后,得来的 AI 使用心法-上
前端·后端·gin
vx-Biye_Design3 小时前
springboot中国传统节日宣传平台49078-计算机课程设计、毕业设计
java·前端·vue.js·spring boot·后端·课程设计·idea