RxJS 过滤运算符执行逻辑深度解析

RxJS 过滤运算符执行逻辑深度解析

核心概念概述

RxJS 是一个强大的响应式编程库,其核心在于 Observable(可观察对象)和操作符(Operators)的灵活组合。本文将深入解析 mapfilter 运算符的执行过程,揭示 RxJS 数据流的处理机制。

示例代码分析

javascript 复制代码
import { of, map, filter } from "rxjs";

const subscriber = of(1, 2, 3, 4, 5)
  .pipe(map((val) => val * 3)) 
  .pipe(filter((val) => val > 7)) 
  .pipe(map((data) => data + 2));

subscriber.subscribe(console.log);

预期输出

复制代码
11
14
17

执行流程详解

1. 创建阶段

of 操作符实现
javascript 复制代码
function fromArrayLike(arrayLike) {
  return new Observable((subscriber) => {
    for (let i = 0; i < arrayLike.length; i++) {
      subscriber.next(arrayLike[i]);
    }
    subscriber.complete();
  });
}
  • 创建一个 Observable 实例
  • 接收数组形式的数据流
  • 依次发送每个元素
  • 最后发送完成通知
Observable 基础结构
javascript 复制代码
export class Observable {
  constructor(subscribe) {
    if (subscribe) {
      this._subscribe = subscribe;
    }
  }
  
  // 惰性执行机制
  subscribe(observerOrNext) {
    const subscriber = new Subscriber(observerOrNext);
    const teardown = this._subscribe(subscriber);
    subscriber.add(teardown);
    return subscriber;
  }
  
  pipe(...operations) {
    return pipeFromArray(operations)(this);
  }
}

关键特性:

  • 惰性执行:只有在订阅时才真正执行
  • 管道机制:支持操作符链式调用

2. 操作符实现原理

map 操作符
javascript 复制代码
export function map(project) {
  return source => {
    return new Observable(function (subscriber) {
      return source.subscribe({
        ...subscriber,
        next: (value) => {
          subscriber.next(project(value));
        },
      })
    });
  }
}

执行逻辑:

  1. 接收转换函数 project
  2. 返回一个接收源 Observable 的函数
  3. 创建一个新的 Observable
  4. 订阅源 Observable 并应用转换
filter 操作符
javascript 复制代码
export function filter(predicate) {
  return source => {
    return new Observable(function (subscriber) {
      return source.subscribe({
        ...subscriber,
        next: (value) => {
          predicate(value) && subscriber.next(value);
        }
      })
    });
  }
}

执行逻辑:

  1. 接收断言函数 predicate
  2. 返回一个接收源 Observable 的函数
  3. 创建一个新的 Observable
  4. 订阅源 Observable 并进行过滤

3. 执行流程分解

构建阶段
  1. of(1,2,3,4,5) 创建初始 Observable
  2. 每个 pipe() 调用都会:
    • 接收操作符函数
    • 返回新的 Observable 实例
  3. 操作链形成但不执行
订阅阶段
  1. 调用 subscribe(console.log) 触发执行
  2. 执行顺序:
    • 最外层的 map 订阅倒数第二层的 filter
    • filter 订阅第一个 map
    • 第一个 map 订阅原始的 of Observable
  3. 数据流处理:
    • of 发出原始值 (1,2,3,4,5)
    • 第一个 map 转换 (3,6,9,12,15)
    • filter 过滤 (>7) → (9,12,15)
    • 最后 map 转换 (+2) → (11,14,17)

核心机制总结

  1. 惰性求值:只有订阅时才真正执行
  2. 操作符组合:每个操作符都返回新的 Observable
  3. 订阅链:形成从外到内的订阅关系
  4. 数据流处理:从源头依次通过各层操作符

可视化流程

scss 复制代码
of(1,2,3,4,5) → map(x3) → filter(>7) → map(+2) → subscribe
      ↓            ↓           ↓           ↓
原始值 1,2,3,4,5 → 3,6,9,12,15 → 9,12,15 → 11,14,17

关键点提醒

  1. 每个 pipe() 都返回新的 Observable 实例
  2. 操作符通过闭包保存转换/过滤逻辑
  3. 订阅是从外向内建立的
  4. 数据流是从内向外传递的
  5. ...subscriber 保留了错误处理和完成通知的能力

理解这些机制有助于编写更高效、可维护的 RxJS 代码,并能够灵活组合各种操作符来处理复杂的数据流场景。

相关推荐
余生H9 个月前
JS异步编程进阶(二):rxjs与Vue、React、Angular框架集成及跨框架状态管理实现原理
javascript·vue.js·react.js·angular·rxjs·异步编程
进二开物1 年前
原来 RxJS 是这样处理复杂数据流
前端·后端·rxjs
chuckchen1 年前
前端开发中的响应式编程
响应式编程·rxjs
进二开物1 年前
给 RxJS 的 Ajax 的功能拦截器
前端·javascript·rxjs
进二开物1 年前
为什么能用 RxJS 取代 Redux ?
前端·javascript·rxjs
进二开物1 年前
RxJS 夯实基础 | 想要的这里都有
前端·后端·rxjs
偏安zzcoder1 年前
Angular系列教程之观察者模式和RxJS
前端·观察者模式·angular.js·rxjs
non_hana2 年前
简单聊聊RxJS中的Observable类和其pipe()方法
前端·typescript·rxjs
进二开物2 年前
详解 RxJS 创建型可观察对象操作符
前端·后端·rxjs