前言

前几篇介绍过了

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. 让你的vscode搭载ChatGPT获得来自 AI 的编程指导

    一直以来,VS Code 都是开发者心目中的生产力神器,它免费.开源且跨平台,被称为最好用的 IDE. 把 VS Code 和 ChatGPT 结合使用,用户将获得来自 AI 的编程指导,包括代码解释 ...

  2. 让摄像头带上智慧“智驭视界·AIEye”

    接上一篇<物联网浏览器(IoTBrowser)-基于计算机视觉开发的应用"智慧眼AIEye">,经过AI的包装很高级,确实很屌炸天. 智驭视界·AIEye 在科技赋能的 ...

  3. django 信号判断是新增、修改还是删除

    在Django的信号处理器中,你可以使用一些方法来确定信号是关于新增(create).修改(update)还是删除(delete)的.这通常涉及到检查 created 和 instance 参数的值. ...

  4. vue中的<script setup>与<script>

    <script setup>是在vue3.2之后新增的语法糖,简化了API的写法 1.声明的变量无需return,可以直接在模板中使用,实现了顶层的绑定 2.引入组件会自动注册,无需再使用 ...

  5. 强化学习算法:Learning to Learn: Meta-Critic Networks for Sample Efficient Learning

    地址: https://arxiv.org/pdf/1706.09529 作者提出了一种叫做Meta-Critic的框架,该框架可以用于强化学习.监督学习等算法中.该算法在强化学习中可以实现元强化学习 ...

  6. 【转载】 新版 Kite为啥这么火,问就俩字『好用』

    本文转自: https://blog.csdn.net/qq_28168421/article/details/102927311 ---------------------------------- ...

  7. Hessian Free Optimization——外国网友分享的“共轭梯度”的推导

    外国网友分享的"共轭梯度"的推导: https://andrew.gibiansky.com/blog/machine-learning/hessian-free-optimiza ...

  8. 局域网环境下,如何在Ubuntu中发现Windows10下的共享文件夹

    参考: https://blog.csdn.net/rangfei/article/details/124225799 ======================================== ...

  9. 再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(2) —— 游戏环境设计篇

    注意: 本文为前文 再探 游戏 < 2048 > -- AI方法-- 缘起.缘灭(1) -- Firefox浏览器自动运行篇 接续篇. ========================== ...

  10. git submodule子模块操作

    背景 为什么使用子模块,因为需要使用其他人维护的公共组件,但这些组件并不是以包或库的形式使用的.所以采用子模块的形式,无论是自己修改还是拉取也很方便. 子模块操作 增加子模块 git submodul ...