前言

前几篇介绍过了

Creation Operators

Filtering Operators

Join Creation Operators

Error Handling Operators

Transformation Operators

Join Operators

这篇继续介绍 Utility Operators

参考

Docs – 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的更多相关文章

  1. cplusplus系列>utility>pair

    http://www.cplusplus.com/reference/utility/pair/ 用于存储一对异构对象 // Compile: g++ -std=c++11 pair.cpp #inc ...

  2. [RxJS] Utility operator: do

    We just saw map which is a transformation operator. There are a couple of categories of operators, s ...

  3. RxJS——调度器(Scheduler)

    调度器 什么是调度器?调度器是当开始订阅时,控制通知推送的.它由三个部分组成. 调度是数据结构.它知道怎样在优先级或其他标准去存储和排队运行的任务 调度器是一个执行上下文.它表示任务在何时何地执行(例 ...

  4. rxjs笔记(未完成)

    首先是 Observable 和promise的区别, 1返回值个数,Observable 可以返回0到无数个值. 2.Promise主动推送,控制着"值"何时被 "推送 ...

  5. ReactiveX Operators

    This documentation groups information about the various operators and examples of their usage into t ...

  6. [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 ...

  7. RxJS入门2之Rxjs的安装

    RxJS V6.0+ 安装 RxJS 的 import 路径有以下 5 种: 1.创建 Observable 的方法.types.schedulers 和一些工具方法 import { Observa ...

  8. Rxjava, RxAndroid, Retrofit 等库的使用

    RxJava的基本用法: 关于 unSubscribe() 的调用问题: There is no need to unsubscribe in onCompleted. Take a look at  ...

  9. ReactiveX 学习笔记(9)工具类操作符

    Observable Utility Operators 本文的主题为处理 Observable 的实用工具类操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(六) ...

  10. Angular 4+ 修仙之路

    Angular 4.x 快速入门 Angular 4 快速入门 涉及 Angular 简介.环境搭建.插件表达式.自定义组件.表单模块.Http 模块等 Angular 4 基础教程 涉及 Angul ...

随机推荐

  1. [oeasy]python0016_编码_encode_编号_字节_计算机

    ​ 编码(encode) 回忆上次内容 上次找到了字符和字节状态之间的映射对应关系 字符对应着二进制字节 二进制字节也对应着字符 这种字节状态是用2位16进制数来表示的 hex(n)可以把数字转化为 ...

  2. RHCA cl210 013 制作镜像 轮转key rabbitmq追踪 写时复制 keystone多域登录图形界面

    undercloud 部署 overcloud overcloud控制节点上的组建rabbitmq 排错需要rabbitmq,开启追踪则会更详细,会消耗性能 环境问题 登录一下classroom os ...

  3. 11、SpringMVC之文件下载和上传

    创建名为spring_mvc_file的新module,过程参考9.1节和9.5节 11.1.文件下载 11.1.1.创建图片目录并放置图片 11.1.2.页面请求示例 <a th:href=& ...

  4. 【MySQL】下发功能SQL

    SQL参考文章: https://www.jb51.net/article/15627.htm 下发,就是从别的表中同步数据到此表中,也可能是来自不同库的表,或者不同实例的表 下发的逻辑要求:如果没有 ...

  5. 【Java】Collections 集合工具类

    Collections 集合工具类 - 操作Set.List.Map等集合的工具 - 提供了排序.查询.修改.操作,提供对对象设置不可变对集合容器对象实现同步控制等方法 排序操作: - static ...

  6. 【Java】JDBC Part6 Apache-DBUtil & Spring-JdbcTemplate

    Apache-DBUtils 开源的JDBC工具类,对JDBC的简单封装 SQL操作交给了QueryRunner的实例 Maven依赖 <!-- https://mvnrepository.co ...

  7. 【Dos-BatchPrograming】03

    --1.AT 计划任务 Microsoft Windows [版本 10.0.19041.746] (c) 2020 Microsoft Corporation. 保留所有权利. C:\Users\A ...

  8. 【转载】 5:0!AI战胜人类教官,AlphaDogfight大赛落幕

    原文:https://baijiahao.baidu.com/s?id=1675621109599102721&wfr=spider&for=pc ------------------ ...

  9. MindSpore 建立神经网络

    代码原地址: https://www.mindspore.cn/tutorial/zh-CN/r1.2/model.html 建立神经网络: import mindspore.nn as nn cla ...

  10. 在oracle中将一行字符串拆分成多行

    例如,有如下一张表,表名为bk_test.插入了以下数据: CREATE TABLE BK_TESK(id varchar2(10),s varchar2(20)); insert into BK_T ...