前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入浅出 RxJS 之 操作符

深入浅出 RxJS 之 操作符

作者头像
Cellinlab
发布2023-05-17 20:13:27
3880
发布2023-05-17 20:13:27
举报
文章被收录于专栏:Cellinlab's Blog

# 为什么要有操作符

一个操作符是返回一个 Observable 对象的函数,不过,有的操作符是根据其他 Observable 对象产生返回的 Observable 对象,有的操作符则是利用其他类型输入产生返回的 Observable 对象,还有一些操作符不需要输入就可以凭空创造一个 Observable 对象。

所有操作符中最容易理解的可能就是 mapfilter ,因为 JavaScript 的数组对象就有这样两个同名的函数 mapfilter

代码语言:javascript
复制
const source = [1, 2, 3, 4];

const result = source.filter(x => x % 2 === 0).map(x => x * 2);

console.log(result);
// [4, 8]

几个关键点:

  • filtermap 都是数组对象的成员函数
  • filtermap 的返回结果依然是数组对象
  • filtermap 不会改变原本的数组对象

因为上面的特点,filtermap 可以链式调用,一个复杂的功能可以分解为多个小任务来完成,每个小任务只需要关注问题的一个方面。此外,因为数组对象本身不会被修改,小任务之间的耦合度很低,这样的代码就更容易维护。

代码语言:javascript
复制
const result$ = source$.filter(x => x % 2 === 0).map(x => x * 2);
result$.subscribe(console.log);

在 RxJS 的世界中,filtermap 这样的函数就是操作符,每个操作符提供的只是一些通用的简单功能,但通过链式调用,这些小功能可以组合在一起,用来解决复杂的问题。

# 操作符的分类

# 功能分类

  • 创建类(creation)
  • 转化类(transformation)
  • 过滤类(filtering)
  • 合并类(combination)
  • 多播类(multicasting)
  • 错误处理类(error Handling)
  • 条件分支类(conditional&boolean)
  • 数学和合计类(mathmatical&aggregate)
  • 其他
    • 背压控制类(backpressure control)
    • 可连接类(connectable)
    • 高阶 Observable(higher order observable)处理类

# 静态和实例分类

所有的操作符都是函数,不过有的操作符是 Observable 类的静态函数,也就是不需要 Observable 实例就可以执行的函数,所以称为“静态操作符”;另一类操作符是 Observable 的实例函数,前提是要有一个创建好的 Observable 对象,这一类称为“实例操作符”。

无论是静态操作符还是实例操作符,它们都会返回一个 Observable 对象。

一个操作符应该是静态的形式还是实例的形式,完全由其功能决定。有意思的是,有些功能既可以作为 Observable 对象的静态方法,也可以作为 Observable 对象的实例方法。

# 如何实现操作符

# 操作符函数的实现

每个操作符都是一个函数,不管实现什么功能,都必须考虑下面这些功能要点:

  • 返回一个全新的 Observable 对象
  • 对上游和下游的订阅及退订处理
  • 处理异常情况
  • 及时释放资源
代码语言:javascript
复制
function map (project) {
  // 返回新的 Observable 对象,可以用于链式调用
  return new Observable(observer => {
    // this 代表上游的 Observable 对象
    const sub = this.subscribe({
      next: value => {
        // 异常捕获,并传递给下游
        try {
          observer.next(project(value))
        } catch (error) {
          observer.error(error)
        }
      },
      // error 和 complete 直接交给下游处理
      error: error => observer.error(error),
      complete: () => observer.complete()
    });

    // 当下游退订时,需要对上游做退订的动作
    return {
      unsubscribe: () => {
        sub.unsubscribe();
      }
    };
  });
}

# 关联 Observable

  1. Observable 打补丁
代码语言:javascript
复制
// 实例操作符
Observable.prototype.map = map;

如果是静态操作符,则是直接赋值给 Observable 类的某个属性。

  1. 使用 bind 绑定特定 Observable 对象
代码语言:javascript
复制
const result$ = map.bind(source$)(project);

代码语言:javascript
复制
const operator = map.bind(source$);
const result$ = operator(project);

  1. 使用 lift

RxJS v5 版本对架构有很大的调整,很多操作符都使用一个神奇的 lift 函数实现,lift 的含义就是“提升”,功能是把 Observable 对象提升一个层次,赋予更多功能。liftObservable 的实例函数,它会返回一个新的 Observable 对象,通过传递给 lift 的函数参数可以赋予这个新的 Observable 对象特殊功能。

代码语言:javascript
复制
function map (project) {
  return this.lift(function (source$) {
    return source$.subscribe({
      next: value => {
        try {
          this.next(project(value))
        } catch (error) {
          this.error(error)
        }
      },
      error: error => this.error(error),
      complete: () => this.complete()
    });
  });
}

Observable.prototype.map = map;

虽然 RxJS v5 的操作符都架构在 lift 上,应用层开发者并不经常使用 lift ,这个 lift 更多的是给 RxJS 库开发者使用。

# 改进的操作符定义

如果严格遵照函数式编程的思想,应该尽量使用纯函数,纯函数的执行结果应该完全由输入参数决定,如果函数中需要使用 this ,那就多了一个改变函数行为的因素,也就算不上真正的纯函数了。定义操作符的函数中访问 this ,实际上违背了面向函数式编程的原则。

  1. 操作符和 Observable 关联的缺陷

无论是静态操作符还是实例操作符,通常在代码中只有用到了某个操作符才导入(import)对应的文件,目的就是为了减少最终的打包文件大小。

用给 Observable “打补丁”的方式导入操作符,每一个文件模块影响的都是全局唯一的那个 Observable

  1. 使用 call 来创建库

对于实例操作符,可以使用前面介绍过的 bind/call 方法,让一个操作符函数只对一个具体的 Observable 对象生效;对于静态操作符,就直接使用产生 Observable 对象的函数,而不是依附于 Observable 的静态函数。

静态操作符不能包含对 this 的访问,所以其实不需要和 Observable 类有任何关系,以前把它们挂在 Observable 类上,纯粹就是为了表示两者有些语义联系而已。

对于实例操作符,因为函数实现要访问 this ,所以需要用 bind 或者 call 的方式来绑定 this

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/7/19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 为什么要有操作符
  • # 操作符的分类
    • # 功能分类
      • # 静态和实例分类
      • # 如何实现操作符
        • # 操作符函数的实现
          • # 关联 Observable
            • # 改进的操作符定义
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档