技术标签: RxJS 前端 javascript 开发语言
本文是简单介绍 RxJS ,帮助新手快速上手RxJS ,更详细的使用方法及API内容可参考 RxJS 官方文档 --RxJS 中文版
RxJS 全称 Reactive Extensions for JavaScript
RxJS 结合了函数式编程、观察者模式(例如 DOM EventListener)、迭代器模式(例如 ES6 Iterater)
RxJS 官方是这样说的: Think of RxJS as Lodash for events. 把 RxJS 想像成针对 events 的 lodash
RxJS 本质是个工具库,处理的是事件,这里的 events,可以称之为流
那么流是指什么呢?举个例子,代码中每 1s 输出一个数字,用户每一次对元素的点击,就像是在时间这个维度上,产生了一个数据集。这个数据集不像数组那样,它不是一开始都存在的,而是随着时间的流逝,数据一个一个被输出。这种异步行为产生的数据,就可以被称之为一个流。在 RxJS 中,称之为 ovservalbe(抛开英文,本质其实就是一个数据的集合,只是这些数据不一定是一开始就设定好的,而是随着时间而不断产生的)
而 RxJS,就是为了处理这种流而产生的工具,比如流与流的合并、流的截断、延迟、消抖等
它的本质其实就是一个随时间不断产生数据的一个集合,称之为流更容易理解。而其对象存在一个 subscribe 方法,调用该方法后,才会启动这个流(也就是数据才会开始产生),这里需要注意的是多次启动的每一个流都是独立的,互不干扰。
从行为上来看,无非就是定义了如何处理上述流产生的数据,称之为流的处理方法。
它的本质就是暂存了一个启动后的流,之前提到,每一个启动后的流都是相互独立的,而这个启动后的流,就存储在 subscription 中,提供了 unsubscribe,来停止这个流。
简单理解了这三个名词 observable, observer, subscription 后,从数据的角度来思考:
observable 定义了要生成一个什么样的数据,其 subscribe 方法,接收一个 observer(定义了接收到数据如何处理),并开始产生数据。该方法的返回值 subscription, 存储了这个已经开启的流,同时具有 unscbscribe 方法,可以将这个流停止。
Subscription = Observable.subscribe (observer)
observable: 随着时间产生的数据集合,可以理解为流,其 subscribe 方法可以启动该流
observer: 决定如何处理数据
subscription: 存储已经启动过的流,其 unsubscribe 方法可以停止该流
它是一个代理对象,既是一个 Observable 又是一个 Observer,它可以同时接受 Observable 发射出的数据,也可以向订阅了它的 observer 发射数据,同时,Subject 会对内部的 observers 清单进行多播 (multicast)
Subjects 是将任意 Observable 执行共享给多个观察者的唯一方式
Subject 有三个变体:
BehaviorSubject是一种在有新的订阅时会额外发出最近一次改变的值的 Subject,需要传入一个参数即初始值(如果没改变则发送初始值)
ReplaySubject会保存所有值,然后回放给新的订阅者,需要传入一个参数即初始值,用于控制重放值的数量(默认重放所有)
AsyncSubject只有当 Observable 执行完成时 (执行 complete()),才会将执行的最后一个值发送给观察者。如果因异常而终止,AsyncSubject 将不会释放任何数据,但是会向 Observer 传递一个异常通知。
Scheduler
用来控制并发并且是中央集权的调度员,允许在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。
调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
调度器是执行上下文。 它表示在何时何地执行任务 (举例来说,立即的,或另一种回调函数机制 (比如 setTimeout 或 process.nextTick),或动画帧)。
调度器有一个 (虚拟的) 时钟。 调度器功能通过它的 getter 方法 now() 提供了 “时间” 的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。
Scheduler调度器能做四种调度:
queue:将每个下一个任务放在队列中,而不是立即执行。queue 延迟使用调度程序时,其行为与 async 调度程序相同。当没有延迟使用时,它将同步安排给定的任务 - 在安排好任务后立即执行。但是,当递归调用时(即在已调度的任务内部),将使用队列调度程序调度另一个任务,而不是立即执行,该任务将被放入队列并等待当前任务完成。
asap:内部基于 Promise 实现(Node 端采用 process.nextTick),会使用可用的最快的异步传输机制,如果不支持 Promise 或 process.nextTick 或者 Web Worker 的 MessageChannel 也可能会调用 setTimeout 方式进行调度。
async:与 asap 方式很像,只不过内部采用 setInterval 进行调度,大多用于基于时间的操作符。
animationFrame:内部基于 requestAnimationFrame 来实现调度,所以执行的时机将与 window.requestAnimationFrame 保持一致,适用于需要频繁渲染或操作动画的场景。
RxJS 操作符(Operators)非常多,在此只介绍几个常用的:
create将 onSubscription 函数转化为一个实际的 Observable 。每当有人订阅该 Observable 的时候,onSubscription 函数会接收 Observer 实例作为唯一参数行。onSubscription 应该调用观察者对象的 next, error 和 complete 方法。
const source = Rx.Observable.create(((observer: any) => {
observer.next(1);
observer.next(2);
setTimeout(() => {
observer.next(3);
}, 1000)
}))
// 方式一
source.subscribe(
{
next(val) {
console.log('A:' + val);
}
}
);
// 方式二
source.subscribe((val) => console.log('B:' + val));
// A:1
// A:2
// B:1
// B:2
//- 1s后:
// A:3
// B:3
从一个数组、类数组对象、Promise、迭代器对象或者类 Observable 对象创建一个 Observable。该方法就有点像 js 中的 Array.from 方法(可以从一个类数组或者可迭代对象创建一个新的数组),只不过在 RxJS 中是转成一个 Observable 给使用者使用。
const source = Rx.Observable.from([10, 20, 30]);
source.subscribe(v => console.log(v));
// 10
// 20
// 30
of
与 from
的能力差不多,只不过在使用的时候是传入一个一个参数来调用的,有点类似于 js
中的 concat
方法。同样也会返回一个 Observable
,它会依次将你传入的参数合并并将数据以同步的方式发出。
const source = Rx.Observable.interval(1000).take(3);
const result = source.debounceTime(2000);
result.subscribe(x => console.log(x));
// 程序启动之后的前三秒没有数据打印,等到五秒到了之后,打印出一个2,接着就没有再打印了
// 数据源会每秒依次发送三个数 0、1、2,由于我们设定了延时时间为 2 秒,那么也就是说,我们在数据发送完成之前都是不可能看到数据的,因为发送源的发送频率为 1 秒,延时时间却有两秒,也就是除非发送完,否则不可能满足发送源等待两秒再发送新数据,每次发完新数据之后要等两秒之后才会有打印,所以不论我们该数据源发送多少个数,最终订阅者收到的只有最后一个数。
只发出源 Observable 最初发出的 N 个值 (N = count)
这个操作符在前面出现了很多次了,还挺常见的,用于控制只获取特定数目的值,跟 interval 这种会持续发送数据的配合起来就能自主控制要多少个值了。
返回一个 Observable, 该 Observable 跳过源 Observable 发出的前 N 个值 (N = count)。
假设这个数据源发送 6 个值,可以使用 skip 操作符来跳过前多少个。
const source = Rx.Observable.from([1, 2, 3, 2, 4, 3]);
const result = source.skip(2);
result.subscribe(x => console.log(x));
// 打印结果为:3、2、4、3,跳过了前面两个数。
concat
concat
和 concatAll
效果是一样的,区别在于 concat
要传递参数,参数必须是 Observable
。
concat
将多个 observable
串接起来,前一个完成好了再执行下一个。
const source1 = interval(1000).pipe(take(3));
const source2 = of(3);
const source3 = of (4,5);
const example = source1.pipe(concat(source2,source3))
example.subscribe({
next: value => {
console.log(value);
},
error: err => {
console.log("Error: " + err);
},
complete: () => {
console.log("complete");
}
});
// 0
// 1
// 2
// 3
// 4
// 5
// complete
在 RxJS 中,有热观察和冷观察的概念。其中的区别:
RxJS 中 Observable 默认为冷观察,而通过 publish() 和 connect() 可以将冷的 Observable 转变成热的
let publisher$ = Rx.Observable.interval(1000).take(5).publish();
publisher$.subscribe(
data => console.log('subscriber from first minute',data),
err => console.log(err),
() => console.log('completed')
)
setTimeout(() => {
publisher$.subscribe(
data => console.log('subscriber from 2nd minute', data),
err => console.log(err),
() => console.log('completed')
)
}, 3000)
publisher$.connect();
// 第一个订阅者输出的是0,1,2,3,4,而第二个输出的是3,4,此处为热观察
热观察和冷观察根据具体的场景可能会有不同的需要,而 Observable 提供的缓存能力也能解决不少业务场景。
例如,如果我们想要在拉群后,自动同步之前的聊天记录,通过冷观察就可以做到。
一般来说,合流有两种方式:
// merge
--1----2-----3--------4---
----a-----b----c---d------
merge
--1-a--2--b--3-c---d--4---
// combine
--1----2-----3--------4---
----a-----b-----c--d------
combine
--1a-2a-2b-3b-3c-3d-4d--
merge 的合流方式可以用在聊天室、多人协作、公众号订阅就可以通过这样的方式合流,最终按照顺序地展示出对应的操作记录。
在 Excel 中,通过函数计算了 A1 和 B2 两个格子的相加。这种情况下可以使用 combine 合流:
const streamA1 = Rx.Observable.fromEvent(inputA1, "input"); // 监听 A1 单元格的 input 事件
const streamB2 = Rx.Observable.fromEvent(inputB2, "input"); // 监听 B2 单元格的 input 事件
const subscribe = combineLatest(streamA1, streamB2).subscribe((valueA1, valueB2) => {
// 从 streamA1 和 streamB2 中获取最新发出的值
return valueA1 + valueB2;
});
// 获取函数计算结果
observable.subscribe((x) => console.log(x));
在一个较大型的前端应用中,通常会拆分成渲染层、数据层、网络层、其他服务等多个功能模块。
虽然服务按照功能结构进行拆分了,但依然会存在服务间调用导致依赖关系复杂、事件触发和监听满天飞等情况。这种情况下,只能通过全局搜索关键字来找到上下游数据流、信息流,通过节点和关键字搜索才能大概理清楚某个数据来源哪里。
如果使用了响应式编程,我们可以通过各种合流的方式、订阅分流的方式,来将应用中的数据流动串在一起。这样,我们可以很清晰地当前节点上的数据来自于哪里,是用户的操作还是来自网络请求。
文章浏览阅读140次。产品概述:WJ183产品是一种物联网和工业以太网采集模块,实现了传感器与网络之间形成透明的数据交互。可以将传感器的模拟量数据转发到网络。
文章浏览阅读40次。2019独角兽企业重金招聘Python工程师标准>>> ..._联动组件数据刷新 props 关联
文章浏览阅读404次,点赞3次,收藏7次。RxPosed:Android逆向工程与模块化框架的革新项目地址:https://gitcode.com/Thehepta/rxposedRxPosed是一个基于XPosed框架的,用于Android应用逆向工程和动态 hook 的库。它利用了ReactiveX(一个用于处理异步数据流的库)的灵活性和强大的功能,为开发者提供了一种全新的方式来操纵应用程序的行为。该项目源自GitCode并开源,...
文章浏览阅读888次,点赞28次,收藏25次。基于SpringBoot的拍卖商城系统设计与实现的课题背景、目的、意义和研究方法如下:课题背景:随着互联网技术的快速发展和移动设备的广泛普及,电子商务已经成为现代社会重要的商业模式之一。在线拍卖作为一种新型的电子商务模式,它结合了传统的拍卖方式与互联网的技术优势,为用户提供了更加便捷、高效的拍卖体验。SpringBoot作为一个轻量级的Java开发框架,以其易用性、灵活性和高度自动化的特点,在开发企业级应用程序中得到了广泛的应用。因此,基于SpringBoot开发拍卖商城系统,不仅可以满足市场对于高效、
文章浏览阅读1.8k次。Python调用DLL例子示例一首先,在创建一个DLL工程(本人是在VS 2005中创建),头文件:[cpp] view plain copy //hello.h #ifdef EXPORT_HELLO_DLL #define HELLO_API __declspec(dllexport) #else _python中怎样调用c语言动态链接库
文章浏览阅读1w次,点赞20次,收藏74次。本专栏为收费专栏的文章目录,对应的免费专栏为《[PyQt入门知识目录](https://blog.csdn.net/laoyuanpython/category_9702362.html)》,两个专栏都为基于PyQt的Python图形界面开发基础教程,只是收费专栏中的内容介绍更深入、案例代码更全。Qt和PyQt介绍的很多部件属性及字典取值在Qt及PyQt官方文档以及网上都没有,老猿通过大量研究、测试将相关内容弄清楚,因此本专栏适合有一定Python基础的同仁零基础学习Python图形界面开发,也适合学习_pythonqt图形界面开发
文章浏览阅读2.3k次。RSS主演互联网变局 盛大新浪只是配角王翌 盛大和新浪的喜筵已近尾声,媒体上铺天盖地猜测着互联网新寡头时代的下一出戏谁来抢?是否该网易或腾讯甚至百度出手了?还有谁没收购?还有谁没被收购? 在很多时候,资本确实有改变产业格局的能力和能量。但是,最富于变化的、发展最快的互联网产业在更多时候是财富的创造者而非资本的附庸!主导互联网发展的,是技术,而不是股价;推动互联网前进的,_技术rss
文章浏览阅读672次,点赞2次,收藏2次。行为预测是指根据当前的环境信息和历史数据,预测其他交通参与者(如行人、车辆)未来的行为。其主要目标是提前识别潜在的危险情况并采取适当的措施,以确保自动驾驶车辆的安全性和可靠性。此外,行为预测还能够为自动驾驶系统提供更高效的路径规划和决策依据。行为预测研究中常用的数据集包括Nuscenes、KITTI、ApolloScape等。这些数据集包含了丰富的场景信息和真实的交通数据,可以用于模型的训练和评估。常用的行为预测评估指标包括准确率、召回率、F1值等。_autoware行为预测
文章浏览阅读1.6k次,点赞3次,收藏5次。JDK、Android SDK、NDK 安装下载,AVD 的创建,以及环境测试等_qt6的andiord
文章浏览阅读1.6k次。云端E课堂简介云端E课堂是云端软件推出的针对云E算力平台使用的免费在线课堂,覆盖量化计算、生物科技、人工智能等领域的实操演示,云端E课堂将邀请诸多领域的大咖为学员提供最贴近实操的内容。课程概况基于结构的虚拟筛选是发现苗头化学物的一个重要计算方法。但海量化合物库使得传统的虚拟筛选方法显得效率不足。虽然哈佛大学医学院的研究人员开发的开源药物发现平台Virtualflow就是针对这个问题的一种..._在线虚拟筛选
文章浏览阅读1.8k次,点赞7次,收藏12次。jacinto 内核驱动 – 43.2.2.10. PCIe端点介绍集成在Jacinto 7中的PCIe控制器IPs能够在根复杂模式(主机)或端点模式(设备)下运行。当在End Point (EP)模式下操作时,控制器可以配置为根据用例使用的任何功能(’ Test endpoint ‘和’ NTB '是目前Linux内核中唯一支持的PCIe EP功能)。框图以下是端点模式框架框图:Features of J7ESJ7ES的特点PCIe子系统有四个实例。以下是一些主要功能:•每个实例都可以配_unssigned class[ff00] : device
文章浏览阅读6.7k次,点赞3次,收藏21次。ksz8863是一款交换芯片,结构如下:有2个完整的MAC + PHY,还有第三路网口,只有一个MAC3,右边是switch逻辑,下边是控制接口,支持i2c/spi/smi1.片子的rmii/mii接口支持2种模式, MAC模式 加 PHY模式, 注意,工作模式是相对于它自身所起的功能所说的,如果它是通过rmii接stm32f437的MAC,它起到一个外置PHY的作用,那它...