RxJS 系列 – Utility Operators
前言
前几篇介绍过了
这篇继续介绍 Utility Operators
参考
tap
tap 是用来写 side effect 的. RxJS 也带有函数式的概念.
一个 Observable 流是没有任何 side effect 的. 如果想搞 side effect 就可以利用 tap operator
from([1, 2, 3])
.pipe(tap(v => console.log('tap: ' + v)))
.subscribe();
效果
tap 不需要返回任何值, upstream 的 value 会自动被传到 downstream. tap 只负责 side effect 就可以了.
delay
顾名思义, 就是延后一个时间才接收.
console.log('start');
from([1, 2, 3])
.pipe(delay(1000))
.subscribe(v => console.log(v));
console.log('end');
下面左图是没有 delay 的效果, 它是同步的, 右图是有 delay 的效果, start end 是同步, 1 秒后 1,2,3 才接收.
你可能好奇为什么不是
1 > delay 1 秒 > 2 > delay 1 秒 > 3
而是
delay 1 秒 1,2,3
关于这点, 可以回看 RxJS 系列 – Scheduler 里面有解释到. 这里不展开了.
delayWhen
delayWhen 是 delay 的底层实现. 下面是 delay 的源码. 里面调用了 delayWhen
delayWhen 接收一个方法, 参数是源 source 发布的值, 返回一个 Observable. 这个 Observable 发布表示 delay 结束.
from([1, 2, 3])
.pipe(delayWhen(v => timer(v * 1000)))
.subscribe(v => console.log(v));
第一个进入 delayWhen 的值是 1. 于是 timer(1 * 1000), 然后 1 秒后发布.
第二个进入的值是 2, timer(2 * 1000) 2 秒后发布
3 就是三秒后发布
最终效果
dematerialize
dematerialize 可以让我们通过 next 的方式输出 next, error, complete 的效果.
例子说明
首先我们有个 Subject. 它发布 ObservableNotification. 这个是 RxJS 的一个特别 interface
const subject = new Subject<ObservableNotification<string>>();
发布长这样
subject.next({ kind: 'N', value: 'next value' });
subject.next({ kind: 'E', error: 'error value' });
subject.next({ kind: 'C' });
kind: 'N' | 'E' | 'C' 分别代表 Next, Error, Complete
接收长这样
subject.pipe(dematerialize()).subscribe({
next: v => console.log('next', v),
complete: () => console.log('complete'),
error: e => console.log('error', e),
});
当发布 kind: 'E', subscribe 就会接收到 error.
当然如果直接调用 subject.complete 或 subject.error, subscribe 依然会收到 complete 和 error, dematerialize 只是扩展了 next 的表达, 并没有破坏任何原本的东西.
materialize
dematerialize 是让 next 变得可以发布 error, complete
materialize 则是把 .complete, .error 变成 next 发布
在 materialize 的情况下, subscribe 永远只需要处理 next, 因为永远都接收不到 complete 和 error
const subject = new Subject<string>(); subject.pipe(materialize()).subscribe({
next: v => console.log(v),
complete: () => console.log('complete'), // never be called
error: e => console.log('error', e), // never be called
}); subject.next('value'); // console: { kind: 'N', value: 'value', error: undefined, hasValue: true }
subject.error('error'); // console: { kind: 'E', value: undefined, error: 'error', hasValue: false }
observeOn, subscribeOn
回看 RxJS 系列 – Scheduler, 里面已经介绍过了.
简单说
subscribeOn 是 delay subscribe, 但没有 delay 后续的发布 (放在 pipe 任何位置效果一样)
observeOn 是 delay 后续的发布, 但是没有 delay 源头 (放在 pipe 的位置不同效果不同)
schedule([1,2,3], asyncScheduler) 是源头开始 delay 发布.
3 种方式表示了不同阶段的 delay
schedule 源头 > observeOn 中间 > subscribeOn 结尾
timeInterval
timeInterval 能让我们知道每一次发布距离上一次间隔了多久.
const subject = new Subject<string>(); subject.pipe(timeInterval()).subscribe(({ value, interval }) => console.log([value, interval])); (async () => {
await delayAsync(2000);
subject.next('first'); await delayAsync(4000);
subject.next('second');
})();
效果
最终接收的 value 被 wrap 了一层对象. 里面包含了间隔时间和原本的值.
第一个 2 秒的间隔是从 subscribe() 开始到第一次的 next 发布. 2005 多了 5ms 是正常的, JS 单线程总是会有微差的.
第二个 4 秒就是从第一次发布到第二次发布的间隔时间.
timestamp
timestamp 和 timeInterval 类似. 只是它返回的不是间隔的 ms. 而是 Epoch Time.
subject.pipe(timestamp()).subscribe(({ value, timestamp }) => console.log([value, timestamp]));
效果
timeout
timeout 的概念就是限定一个时间内, 必须完成任务, 没有完成就一个特殊处理.
用在 RxJS 指的是一个 stream 必须在 timeout 限制的时间内, 完成发布. 没有发布就 failure, 然后就一个特殊处理.
const subject = new Subject<string>();
subject
.pipe(
timeout({
each: 2000,
})
)
.subscribe({
next: () => console.log('next'),
error: e => console.log('error', e),
complete: () => console.log('complete'),
});
上面的 timeout 要求 subject 从 subscribe() 开始, 每一次发布间隔都不可以超出 2 秒
(async () => {
await delayAsync(1000);
subject.next('ok1'); // 可以
await delayAsync(1500);
subject.next('ok2'); // 可以
await delayAsync(2500); // timeout error, 从上一次发布已经超过了要求的 2 秒
subject.next('ok3');
})();
效果
一旦超过时间, 就会触发 error
first
把 each 改成 first, 就变成只限制第一次的发布必须在时间内.
timeout({
first: 2000,
})
效果
没有 error 了, 因为第一次发布在限定的 2 秒就 ok 了
Date
first 还支持绝对时间
timeout({
first: new Date(2023, 1, 1),
})
只要在 01-01-2023 前发布就 ok, 超过这个时间就报错.
custom error handle
如果不希望 throw error, 我们可以自己设定处理方式
timeout({
first: 1000,
with: info => {
console.log(info);
return EMPTY;
},
})
效果
通过 with 返回一个 Observable, downstream 会 subscribe 它. 上面例子我返回 EMPTY, 所以就进入了 subscribe 的 complete.
shorthand
timeout(1000)
// 相等于
timeout({ each: 1000 }) timeout(new Date())
// 相等于
timeout({ first: new Date() })
toArray
toArray 有点像 buffer, 但是它比较简单明了.
当 Observable 还没有 complete 前, 所以发布的值会被保存起来, 不会接收.
一直到 Observable complete 以后, subscrube 会一次性接收到所有之前保存的值. 以 array 的方式接收.
const subject = new Subject<number>();
subject.pipe(toArray()).subscribe(v => console.log(v));
subject.next(1);
subject.next(2);
subject.next(3); // 到这里都不会触发 console
subject.complete(); // console: [1, 2, 3]
废弃了的 Transformation Operators
timeoutWith
一句话总结
tap : 处理 side effect
delay : 延迟发布 by 时间
delayWhen : 延迟发布 by Observable
dematerialize : next 可以发布 complete 和 error
materialize : 把 complete 和 error 变成 next 发布
subscribeOn : delay subscribe, 但没有 delay 后续的发布 (放在 pipe 任何位置效果一样)
observeOn : delay 后续的发布, 但是没有 delay 源头 (放在 pipe 的位置不同效果不同)
timeInterval : wrap value with 从上一次发布到这一次的时间间隔
timestamp : wrap value with epoch time
timeout : 超时任务就特殊处理
toArray : 缓存所有 values 直到 complete 后一次性接收 by Array 形式
RxJS 系列 – Utility Operators的更多相关文章
- cplusplus系列>utility>pair
http://www.cplusplus.com/reference/utility/pair/ 用于存储一对异构对象 // Compile: g++ -std=c++11 pair.cpp #inc ...
- [RxJS] Utility operator: do
We just saw map which is a transformation operator. There are a couple of categories of operators, s ...
- RxJS——调度器(Scheduler)
调度器 什么是调度器?调度器是当开始订阅时,控制通知推送的.它由三个部分组成. 调度是数据结构.它知道怎样在优先级或其他标准去存储和排队运行的任务 调度器是一个执行上下文.它表示任务在何时何地执行(例 ...
- rxjs笔记(未完成)
首先是 Observable 和promise的区别, 1返回值个数,Observable 可以返回0到无数个值. 2.Promise主动推送,控制着"值"何时被 "推送 ...
- ReactiveX Operators
This documentation groups information about the various operators and examples of their usage into t ...
- [RxJS] Split an RxJS observable with window
Mapping the values of an observable to many inner observables is not the only way to create a higher ...
- RxJS入门2之Rxjs的安装
RxJS V6.0+ 安装 RxJS 的 import 路径有以下 5 种: 1.创建 Observable 的方法.types.schedulers 和一些工具方法 import { Observa ...
- Rxjava, RxAndroid, Retrofit 等库的使用
RxJava的基本用法: 关于 unSubscribe() 的调用问题: There is no need to unsubscribe in onCompleted. Take a look at ...
- ReactiveX 学习笔记(9)工具类操作符
Observable Utility Operators 本文的主题为处理 Observable 的实用工具类操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(六) ...
- Angular 4+ 修仙之路
Angular 4.x 快速入门 Angular 4 快速入门 涉及 Angular 简介.环境搭建.插件表达式.自定义组件.表单模块.Http 模块等 Angular 4 基础教程 涉及 Angul ...
随机推荐
- 自己理解的TCP三次握手
### TCP 三次握手过程是怎样的? TCP的建立连接是通过三次握手来进行的.三次握手的过程如下图: 说实话这个很好理解,我称之为N字型 首先我们理解到建立连接是一个虚的概念了对吧?那么我们来设计一 ...
- vscode取消json文件注释下划线
使用 vscode 打开一个json文件,如果有单行或多行注释,则会显示红色下划线,解决办法如下: 方法1 点击底部的JSON,选择 JSON with Comments 即可,然后红色下划线消失,底 ...
- docker 容器迁移到其他机器
docker 容器迁移到其他机器思路为:容器转为镜像,再保存为镜像文件,迁移到其他机器后导入为镜像 1.commit:将容器转镜像 # docker commit {container_id} {镜像 ...
- 【.bat】IISExpress配置通过IP访问程序
本页只记录便携运行方式脚本 详细IISExpress配置方法请看: VS的IISExpress配置通过IP访问程序 网络信息:192.168.1.45:8378 Run.bat :: run as a ...
- RHCA cl210 015 实例启动 超融合 热迁移 网络underlay
lab computeresources-hci setup 实例启动流程 keystone不仅做认证,且有所有组键地址 nova-conductor解耦,不允许nova-compute直接访问dat ...
- 亲测可用的 Linux(Ubuntu18.04下)可运行的超级玛丽奥(gym-super-mario-bros)游戏的仿真环境—————————可用于强化学习算法的游戏模拟器环境
与前文中的俄罗斯方块游戏一样都是可以用于强化学习算法的游戏模拟器,这里介绍的是超级玛丽奥(gym-super-mario-bros)游戏的仿真环境. Python库,代码地址: https://git ...
- deepin国产操作系统 nvidia-docker2 的安装
====================================== 平时偶尔使用deepin系统,突然有个 nvidia-docker 的程序需要运行,平时工作都是在用Ubuntu,所以对d ...
- Inno Setup 寻找 AppId 的方法
背景 有时候打包后,会遗失AppId.这样会导致下一次打包时没办法和之前统一.为了避免这个问题,所以最好是打包时记下来,可以根据注册表去查 解决办法 可以根据任意查找注册表的工具,我这里使用 Regi ...
- Python 环境傻瓜式搭建 :Anaconda概述
Anaconda概述 Anaconda是一个用于科学计算的Python发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存.切 ...
- 圆方树学习笔记 & 最短路 题解
前言 圆方树学习笔记,从一道例题讲起. 题目链接:Hydro & bzoj. 题意简述 仙人掌上求两点距离. 题目分析 为了把仙人掌的性质发挥出来,考虑将其变成一棵树.圆方树就是这样转换的工具 ...