详解 RxJS 创建型可观察对象操作符

一、简介

RxJS 中可以使用构造函数创建可观察对象,但是这种方式明显的就是效率不高。于是 RxJS 针对不同的业务场景,实现了不同的可观察对象的创建操作符。

二、HTTP 请求

ajax

ts 复制代码
import { ajax } from 'rxjs/ajax';

const ob$ = ajax('your_url').subscribe({})
const ob$ = ajax.getJSON('your_url').subscribe({})
const ob$ = ajax({
    url: 'your_url',
    method: 'POST',
    headers: {
        // your headers
    },
    body: {
        // your body
    }
}).subscribe({})

ajax 大致与 jQuery 时代的 ajax 使用基本一致,只是此处的 ajax 返回的是一个可观察对象。可以订阅这些可观察对象,获取到可观察对象的返回值。当然你可以在可观察对象的 pipe 中处理 ajax 的返回值,然后给订阅对象。

三、回调函数

  • bindCallback
  • bindNodeCallback

bindCallback

绑定回调函数,回调函数一般放在函数参数的最后位置,一个简单的示例:

ts 复制代码
import { bindCallback } from 'rxjs';

const fnCb = (a,b, cb) => {
    cb(a, b, {p: 1})
}
const boundFnCb = bindCallback(fnCb);
boundFnCb('3', 'c').subscribe({
    next(v) {console.log(v)} // [ '3', 'c', { p: 1 } ]
})

自动执行 callback, 并且组合参数到数组中。

bindNodeCallback

绑定 node.js 中的回调函数,以 fs 为例,使用读取文件为例:

ts 复制代码
import { bindNodeCallback } from 'rxjs'
import * as fs from 'fs'

const readFile = bindNodeCallback(fs.readFile)


readFile('./groupBy.js', 'utf-8').subscribe({
  next(v) {
    console.log(v) // 具体的文件的内容
  }
})

四、时间

defer

延迟创建可观察对象,具有了懒的特性,只有在订阅了才创建。

ts 复制代码
import { defer, of } from 'rxjs'

const d$ = defer(() => of(1,2,3))
d$.subscribe({
    next(v) {console.log(v)}
})

of 操作符是一个创建型的操作符,直接使用 of 操作符,经过 defer 包裹之后,它就不会直接创建。当我们订阅之后,这个可观察对象才会被创建。

timer

timer 可以接受三个参数作为参数:

  • dueTime: (number/Date) 等待时间
  • intervalOrScheduler: 定时器或i这调度器
  • scheduler: 可选的调度器
ts 复制代码
import { timer, interval, of } from 'rxjs';

timer(1000)
  .pipe(concatMap(() => of(1, 2, 3)))
  .subscribe({
      next(v) {console.log(v)}
  });

timer(0, 1000).subscribe(n => console.log('timer', n));

interval

创建定时器可观察对象

ts 复制代码
interval(1000).subscribe(n => console.log('interval', n));

实现与 timer 传递第二个参数时可以等价实现。

五、数据范围

range 指定范围

使用 range 操作符创建一个范围:

ts 复制代码
import { range } from 'rxjs';
 
const numbers = range(1, 3);
 
numbers.subscribe({
  next: value => console.log(value),
  complete: () => console.log('Complete!')
});

此时与效果 of(1,2,3) 相似。

generate

range 是指定数字范围,generate 可以根据条件生成,执行不同的条件生成不同的数据。generate 可以接受的参数比较多,所以比 range 要更加灵活的生成数据。

  • init: 指定初始状态
  • condition: 终止生成条件
  • iterate: 迭代步长函数
  • resultSelector: 结果选择器
  • scheduler: 调度器
ts 复制代码
import { generate } from "rxjs";

const initialState = 0;
const condition = (x) => x < 10;
const iterate = (x) => x + 1;
const resultSelector = (x) => x;

const result = generate({ initialState, condition, iterate, resultSelector });
result.subscribe((x) => console.log(x));

💌💌💌由于 generate 一些写法已经被废弃,这里推荐使用对象的方法进行处理。

六、空值

empty 函数已经被废弃,使用 EMPTY 常量来代替,订阅时不会触发 next 方法,直接完成。

ts 复制代码
import { EMPTY } from 'rxjs';

EMPTY.subscribe({
  complete: () => console.log('Complete!')
});

因为不会触发 next 方法,这里就不写了,直接调用 complete。

七、错误处理

throwError 抛出错误可观察对象。参数是一个函数(推荐使用函数):

ts 复制代码
import { throwError } from 'rxjs'

throwError(() => new Error('my error')).subscribe({
  error(e) {console.log(e)}
})

当然 throwError 是处理错误的创建型函数,在 RxJS 也可以直接抛出一个 JavaScript 错误 new Error()

八、js 基础类型值(静态值)

of

ts 复制代码
import { of } from 'rxjs';

// 情况
of(10, 20, 30).subscribe({next(v) { console.log(v) }) // 发出 10 发出 20 发出 30
of([10, 20, 30]).subscribe({next(v) { console.log(v) }) // 发出 [10 20 30]

of 特点是可以接受多个参数,每一个参数单独发射。of 操作符值配合静态数据非常合适

from

from 与 of 不同的,from 接受一个迭代器 iterator 作为参数。当然数组是可以迭代的,下面以数组为例:

ts 复制代码
import { from } from 'rxjs';

const array = [10, 20, 30];
const result = from(array);

from 解释一个迭代器参数,发射数据的时候,迭代数据发射。

九、事件(dom)

当然 RxJS 在处理 dom 事件时,也很方便,fromEvent 传递 dom 即可获取当前的 dom 的可观察对象。

fromEvent

ts 复制代码
import { fromEvent } from 'rxjs';

const clicks = fromEvent(document, 'click');
clicks.subscribe(x => console.log(x));

fromEvent 指定 dom 和 dom 对应的事件作为可观察对象。

值得注意的是:fromEvent 是一个热可观察对象。事件有多个监听器,所有 fromEvent 算是热可观察对象,具有多播的特性。

fromEventPattern

fromEventPattern 是 fromEvent 底层版本,需要两个参数,一个是订阅、一个是移除订阅。

ts 复制代码
import { fromEventPattern } from 'rxjs';

function addClickHandler(handler) {
  // 订阅
}

function removeClickHandler(handler) {
  // 移除订阅
}

const clicks = fromEventPattern(
  addClickHandler,
  removeClickHandler
);
clicks.subscribe(x => console.log(x));

明显 fromEventPattern 对于订阅有更多的操作性,如果是简单的 dom 操作使用 fromEvent 即可。

十、条件

iif

iif 是一个条件创建可观察对象。接受三个参数作为参数:

  • 第一个是一个函数,返回一个布尔值
  • 第二个参数:可观察对象
  • 第三个参数:可观察对象
ts 复制代码
import { iif, of } from 'rxjs';
 
let cond;
const who$ = iif(
  () => cond,
  of('first'),
  of('second')
);

cond = false // 指定第一个参数的返回值
who$.subscribe({
    next(v) {console.log(v)}
})

十一、小结

本文将创建型操作符大致分为 9 块内容,都是一些非常常见的 JS 适用场景,包含 dom 事件、ajax 请求、数据、条件判断、回调函数、错误等。这些操作符式为了方便在业务场景使用时快速的创建可观察对象。如果要熟练精通 RxJS 这些操作符的熟练程度要非常高。

系列文章

相关推荐
初遇你时动了情1 分钟前
react 项目打包二级目 使用BrowserRouter 解决页面刷新404 找不到路由
前端·javascript·react.js
乔峰不是张无忌33020 分钟前
【HTML】动态闪烁圣诞树+雪花+音效
前端·javascript·html·圣诞树
鸿蒙自习室28 分钟前
鸿蒙UI开发——组件滤镜效果
开发语言·前端·javascript
m0_7482507435 分钟前
高性能Web网关:OpenResty 基础讲解
前端·openresty
机器之心1 小时前
图学习新突破:一个统一框架连接空域和频域
人工智能·后端
前端没钱1 小时前
从 Vue 迈向 React:平滑过渡与关键注意点全解析
前端·vue.js·react.js
NoneCoder1 小时前
CSS系列(29)-- Scroll Snap详解
前端·css
无言非影1 小时前
vtie项目中使用到了TailwindCSS,如何打包成一个单独的CSS文件(优化、压缩)
前端·css
.生产的驴2 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
我曾经是个程序员2 小时前
鸿蒙学习记录
开发语言·前端·javascript