RxJS中的Observable和Observer示例详解

目录
  • 引言
  • 概念
  • 牛刀小试
  • Observable
    • Observable 剖析
  • Observer
  • 结束语

引言

最近在项目当中别的小伙伴使用到了Rxjs,我一眼看上去有点懵,感觉挺复杂,挺绕的。于是抓紧补补课,然后就可以和小伙伴们一起交流怎么能优雅的使用Rxjs。由于内容比较多,会分为三篇来讲解说明

  • 初识 RxJS中的 ObservableObserver
  • 细说 RxJS中的 Operators
  • 在谈 RxJS中的 SubjectSchedulers

概念

RxJS是一个库,可以使用可观察队列来编写异步和基于事件的程序的库。

RxJS 中管理和解决异步事件的几个关键点:

  • Observable: 表示未来值或事件的可调用集合的概念。
  • Observer: 是一个回调集合,它知道如何监听 Observable 传递的值。
  • Subscription: 表示一个 Observable 的执行,主要用于取消执行。
  • Operators:** 是纯函数,可以使用函数式编程风格来处理具有mapfilterconcatreduce等操作的集合。
  • Subject: 相当于一个EventEmitter,也是将一个值或事件多播到多个Observers的唯一方式。
  • Schedulers 是控制并发的集中调度程序,允许我们在计算发生在 eg setTimeoutor requestAnimationFrame或者其它上时进行协调。

牛刀小试

我们通过在dom上绑定事件的小案例,感受一下Rxjs的魅力。

  • 在dom绑定事件,我们通常这样处理
document.addEventListener('click', () => console.log('Clicked!'));

用Rxjs创建一个observable,内容如下

import { fromEvent } from 'rxjs';
fromEvent(document, 'click').subscribe(() => console.log('Clicked!'));
  • 这时候我们简单升级一下,需要记录一下点击的数量
let count = 0;
document.addEventListener('click', () => console.log(`Clicked ${++count} times`));

用Rxjs可以隔离状态,

import { fromEvent, scan } from 'rxjs';
fromEvent(document, 'click')
  .pipe(scan((count) => count + 1, 0))
  .subscribe((count) => console.log(`Clicked ${count} times`));

可以看到,我们用到了scan操作符,该操作符的工作方式和数组的reduce类似,回调函数接收一个值, 回调的返回值作为下一次回调运行暴露的一个值。

通过上面的案例可以看出,RxJS的强大之处在于它能够使用纯函数生成值。这意味着您的代码不太容易出错。 通常你会创建一个不纯的函数,你的代码的其他部分可能会弄乱你的状态。

  • 这时候,需求又有变动了,要求我们一秒内只能有一次点击
let count = 0;
let rate = 1000;
let lastClick = Date.now() - rate;
document.addEventListener('click', () => {
  if (Date.now() - lastClick >= rate) {
    console.log(`Clicked ${++count} times`);
    lastClick = Date.now();
  }
});

使用Rxjs

fromEvent(document, 'click')
  .pipe(
    throttleTime(1000),
    scan((count) => count + 1, 0)
  )
  .subscribe((count) => console.log(`Clicked ${count} times`));

RxJS 有一系列的操作符,可以帮助你控制事件如何在你的 observables 中流动。

  • 这时候,我们要每次累计鼠标x的值
let count = 0;
const rate = 1000;
let lastClick = Date.now() - rate;
document.addEventListener('click', (event) => {
  if (Date.now() - lastClick >= rate) {
    count += event.clientX;
    console.log(count);
    lastClick = Date.now();
  }
});

使用Rxjs

import { fromEvent, throttleTime, map, scan } from 'rxjs';
fromEvent(document, 'click')
  .pipe(
    throttleTime(1000),
    map((event) => event.clientX),
    scan((count, clientX) => count + clientX, 0)
  )
  .subscribe((count) => console.log(count));

从上面看可以通过map去转换observables 的值。

Observable

我们先来写一个案例代码,大家可以猜下它的执行顺序

import { Observable } from 'rxjs';
const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  setTimeout(() => {
    subscriber.next(4);
    subscriber.complete();
  }, 1000);
});
console.log('just before subscribe');
observable.subscribe({
  next(x) { console.log('got value ' + x); },
  error(err) { console.error('something wrong occurred: ' + err); },
  complete() { console.log('done'); }
});
console.log('just after subscribe');

可以稍微想一下,正确的输出结果

just before subscribe
got value 1
got value 2
got value 3
just after subscribe
got value 4
done

怎么样,和大家想的结果一样吗,我们来一下分析一下。

Observable 剖析

Observable 有两种方式创建,一种是通过new Observable(),还有一种是通过Rx.Observable.create()的方式去创建。

Observable 核心的关注点:

  • 创建Observable
  • 订阅Observable
  • 执行Observable
  • 取消Observable

创建Observable

const observable = new Observable(function subscribe(subscriber) {
  const id = setInterval(() => {
    subscriber.next('hi')
  }, 1000);
});

该代码是创建一个Observable,然后每隔1s向订阅者发送消息。我们看到上边的回调函数是subscribe, 该函数是描述Observable最重要的部分。

  • 订阅Observable
observable.subscribe(x => console.log(x));

observable中的subscribe中参数是一个回调x => console.log(x),官方叫它Observer,其实Observer有多种形式,后边我们会说到,在这里就简单理解,Observer 可以去消费数据,比如,在react中,我们这可以更新状态数据等。

  • 执行Observable
 subscriber.next(1);   // Next 通知
 subscriber.complete(); // 完成 通知
 subscriber.error(err);  // Error 通知

其实就是执行一个惰性计算,可同步可异步,

Observable Execution 可以传递三种类型的值:

  • Next:发送数值、字符串、对象等。
  • Error:发送 JavaScript 错误或异常。
  • complete:不发送值。

Next通知是最重要和最常见的类型:它们代表传递给订阅者的实际数据。在 Observable 执行期间,Errorcomplete通知可能只发生一次,并且只能有其中之一。

  • 取消Observable
function subscribe(subscriber) {
  const intervalId = setInterval(() => {
    subscriber.next('hi');
  }, 1000);
  return function unsubscribe() {
    clearInterval(intervalId);
  };
}
const observable = new Observable(subscribe)
const unsubscribe = observable.subscribe({next: (x) => console.log(x)});
// Later:
unsubscribe(); // 取消执行

我们有看代码,创建了一个每秒输出一个hi内容的Observable,但在我们的使用场景中,会有取消改行为,这时候就需要返回一个unsubscribe的方法,用于取消。

Observer

我们在上边的场景中也提到了Observer, 但什么是Observer呢,其实就是数据的消费者,先回顾一下上面的代码

observable.subscribe(x => console.log(x));

其实可以写成

const observer = {
  next: x => console.log('Observer got a next value: ' + x),
  error: err => console.error('Observer got an error: ' + err),
  complete: () => console.log('Observer got a complete notification'),
};
observable.subscribe(observer);

这样应就比较清晰了,observer只是具有三个回调的对象,每一个用于Observable 可能传递不同类型的通知。注意,observer 对象中的类型可以不必要全都写。

其实observer有许多变种,我们看下它的TS声明就比较清楚了。

可以直接传递一个observer对象,或者只传递一个next回调函数,在或者传多个可选的回调函数类型。

结束语

RxJS不建议大家盲目的去用,一定要有合适的场景,盲目的去用可能会造成项目的复杂度会大幅度的提升。

以上就是RxJS中的Observable和Observer示例详解的详细内容,更多关于RxJS Observable Observer的资料请关注我们其它相关文章!

(0)

相关推荐

  • 使用RxJS更优雅地进行定时请求详析

    在用 Angular 做项目的时候,遇到了一个有点麻烦的问题.具体问题如下: 轮循请求某个接口,如何保证接口返回的数据与请求的顺序相同? 实际的业务场景是这样的:前端需要轮循请求后端接口获取文件处理进度,并在前端用进度条展示.如下方所示: 首先想到的肯定是使用 setTimeout 或者 setInterval 进行定时请求.然而结果有点诡异,进度条的变化不是递增,而是有快有慢,比如 30%,20%,50%,40%这样.仔细一想也知道问题出在哪,异步请求的结果并不是按顺序返回的. 我在之前的工作

  • RxJS的入门指引和初步应用

    前言 RxJS是一个强大的Reactive编程库,提供了强大的数据流组合与控制能力,但是其学习门槛一直很高,本次分享期望从一些特别的角度解读它在业务中的使用,而不是从API角度去讲解. RxJS简介 通常,对RxJS的解释会是这么一些东西,我们来分别看看它们的含义是什么. Reactive Lodash for events Observable Stream-based 什么是Reactive呢,一个比较直观的对比是这样的: 比如说,abc三个变量之间存在加法关系: a = b + c 在传统

  • 关于RxJS Subject的学习笔记

    Observer Pattern 观察者模式定义 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己. 我们可以使用日常生活中,期刊订阅的例子来形象地解释一下上面的概念.期刊订阅包含两个主要的角色:期刊出版方和订阅者,他们之间的关系如下: 期刊出版方 - 负责期刊的出版和发行工作 订阅者 - 只需执行订阅操作,新版的期刊发布后,就会主动收

  • RxJS在TypeScript中的简单使用详解

    1. 安装 # 安装 typescript, rxjs 包 npm install -D typescript @types/node npm install rxjs 2. 使用 2.1 使用 from 来从数组生成源 RxJS 有许多创建源的方法,如 from, fromEvent..., 这里使用 from做个例子 import {from} from 'rxjs' // 从数组生成可订阅对象 // obser 的对象类型为 Observable let obser = from([1,2

  • RxJS中的Observable和Observer示例详解

    目录 引言 概念 牛刀小试 Observable Observable 剖析 Observer 结束语 引言 最近在项目当中别的小伙伴使用到了Rxjs,我一眼看上去有点懵,感觉挺复杂,挺绕的.于是抓紧补补课,然后就可以和小伙伴们一起交流怎么能优雅的使用Rxjs.由于内容比较多,会分为三篇来讲解说明 初识 RxJS中的 Observable 和 Observer 细说 RxJS中的 Operators 在谈 RxJS中的 Subject和Schedulers 概念 RxJS是一个库,可以使用可观察

  • Go语言中的字符串处理方法示例详解

    1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号("")或反引号(``)定义. 双引号:"", 用于单行字符串. 反引号:``,用于定义多行字符串,内部会原样解析. 示例: // 单行 "心有猛虎,细嗅蔷薇" // 多行 ` 大风歌 大风起兮云飞扬. 威加海内兮归故乡. 安得猛士兮守四方! ` 字符串支持转义

  • C++中#include头文件的示例详解

    fstream是C++ STL中对文件操作的合集,包含了常用的所有文件操作.在C++中,所有的文件操作,都是以流(stream)的方式进行的,fstream也就是文件流file stream. 最常用的两种操作为: 1.插入器(<<) 向流输出数据.比如说打开了一个文件流fout,那么调用fout<<"Write to file"<<endl;就表示把字符串"Write to file"写入文件并换行. 2.析取器(>>

  • Python中bisect的用法及示例详解

    bisect是python内置模块,用于有序序列的插入和查找. 查找: bisect(array, item) 插入: insort(array,item) 查找 import bisect a = [1,4,6,8,12,15,20] position = bisect.bisect(a,13) print(position) # 用可变序列内置的insert方法插入 a.insert(position,13) print(a) 输出: 5 [1, 4, 6, 8, 12, 13, 15, 2

  • Python中三种花式打印的示例详解

    目录 1. 引言 2. 打印圣诞树 2.1 问题描述 2.2 问题分析 3. 打印字母版圣诞树 3.1 问题描述 3.2 问题分析 4. 打印字母版菱形 4.1 问题描述 4.2 问题分析 5. 总结 1. 引言 在Python中有很多好玩的花式打印,对厉害的高手来说可能是小菜一碟,对入门的小白来说往往让人望而退步,我们今天就来挑战下面三个常见的花式打印吧... 2. 打印圣诞树 2.1 问题描述 编码实现函数christmas_tree(height),该函数输入参数为一个整数表示圣诞树的高度

  • 详解Python中生成随机数据的示例详解

    目录 随机性有多随机 加密安全性 PRNG random 模块 数组 numpy.random 相关数据的生成 random模块与NumPy对照表 CSPRNG 尽可能随机 os.urandom() secrets 最佳保存方式 UUID 工程随机性的比较 在日常工作编程中存在着各种随机事件,同样在编程中生成随机数字的时候也是一样,随机有多随机呢?在涉及信息安全的情况下,它是最重要的问题之一.每当在 Python 中生成随机数据.字符串或数字时,最好至少大致了解这些数据是如何生成的. 用于在 P

  • Go语言中循环语句使用的示例详解

    目录 一.概述 1. 循环控制语句 2. 无限循环 二.Go 语言 for 循环 1. 语法 2. for语句执行过程 3. 示例 4. For-each range 循环 三.循环嵌套 1. 语法 2. 示例 四.break 语句 1. 语法 2. 示例 五. continue 语句 1. 语法 2. 示例 六.goto 语句 1. 语法 2. 示例 一.概述 在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句. 循环程序的流程图: Go 语言提供了以下几种类型循环

  • Python中字典常用操作的示例详解

    目录 前言 初始化 合并字典 字典推导式 Collections 标准库 字典转 JSON 字典转 Pandas 前言 字典是Python必用且常用的数据结构,本文梳理常用的字典操作,看这个就够了,涉及: 初始化 合并字典 字典推导式 Collections 标准库 字典转JSON 字典转Pandas 初始化 # 最常用这种 my_object = { "a": 5, "b": 6 } # 如果你不喜欢写大括号和双引号: my_object = dict(a=5,

  • C#面向对象编程中接口隔离原则的示例详解

    目录 接口隔离原则 C# 示例 糟糕的示范 正确的示范 总结 在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原则的子集,在他2000年的论文<设计原则与设计模式>中首次提出. SOLID 原则包含: S:单一功能原则(single-responsibility principle) O:开闭原则(open-closed principle) L

  • C#面向对象编程中里氏替换原则的示例详解

    目录 里氏替换原则 C# 示例 糟糕的示范 正确的示范 总结 在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原则的子集,在他2000年的论文<设计原则与设计模式>中首次提出. SOLID 原则包含: S:单一功能原则(single-responsibility principle) O:开闭原则(open-closed principle) L

随机推荐