RxJS 夯实基础 | 想要的这里都有

一、简介

从 2023 年 NestJS 的学习与实践中发现,RxJS 在 NestJS gRPC 微服务中扮演重要角色,gRPCproto 文件生成 TS 类型文件式,使用可观察对象,而不是 Promise。

面对 NestJS 和 Angular 系列,如果对 RxJS 不熟悉,就像多年前都端开发者不熟悉 webpack 一样。

多年以后回顾 webpack, 学习 RxJS 的场景就跟以前简直一模一样。

为了更好的学习并全面的掌握 RxJS, 本文以 RxJS 基础为核心用有文字图片、配合视频方式讲解,希望能够帮助到大家。

RxJS 是一个函数式的响应式可观察对象编程库。

二、可观察对象基础

RxJS 中可观察对象 Observable最基础 的内容,没有学习过 RxJS 也不用担心,可观察对象本身只是一个,很简单并且很少直接使用。

我们需要知道的是:可观察对象会创建 数据流。(如果你更加习惯观看视频,可以观看以下的视频,关于 RxJS 可观察对象的讲解。)

三、pipe 函数

pipe可观察对象构造函数 Observable 的实例方法。

pipe 函数很好理解:是数据流的操作管道。在管道中,可以调用 操作符函数 处理流入的数据。

四、操作符

操作符是 RxJS 中最难得部分,难在什么地方?

使用场景多,操作符多,需要基础牢固和实战经验,才能灵活运用 RxJS

五、创建型操作符

创建型操作符:是 RxJS 内置一些常用的操作符函数,方便日常使用的操作符。需要注意的它调用函数的返回值是 可观察对象,像常见的内容有哪些。

✅创建型操作符一共包含 15 个操作符

六、Join 创建型操作符

创建型操作符一共包含 7 个操作符

操作符 说明 观看视频
🍭combineLatest combineLatest 用于将多个 Observables 的最新值合并成一个新的值,并且当其中任何一个 Observable 发出新值时都会触发这个合并。
🍭concat concat 用于将多个 observables 按顺序串联起来。它会按照顺序订阅并依次发出每个 observable 的值,只有前一个 observable 完成(complete)后,才会订阅下一个 observable
🍭forkJoin forkJoin 是一个 RxJS 中的操作符,它可以将多个 Observable 组合成一个新的 Observable,等待所有的 Observable 完成,然后将它们的最新值作为数组发出。
🍭merge merge 可以将多个 Observable 流合并成一个。它会同时订阅所有的 Observable,然后按照它们发出值的顺序将这些值合并成一个单一的 Observable 流。
🍭partition partition 用于将 Observable 拆分为两个 Observables,一个满足特定条件,另一个不满足该条件。
🍭race race 允许你在多个 Observable 中进行竞速。它会观察多个 Observables,并只发出首先发出值或完成的 Observable 的数据。
🍭zip zip 用于将多个 Observables 的数据配对合并成一个新的 Observable。这个新的 Observable 发出的数据是由每个输入 Observable 相应位置的数据配对而成的数组。

七、转换类型操作符

✅转换型操作符一共有 28 个操作符

7.1) 🍀buffer 系列

| 操作符 | 说明 |
|------------------|------------------------------------------------------------------------------------------------------------------------------|---|
| 🍭buffer | buffer 允许你根据另一个 Observable 的信号来决定何时发出缓冲区的数组。它接受一个 closingNotifier 参数,当这个 closingNotifier 发出信号时,buffer 会发出当前缓冲区中的值并重新开始缓冲 | |
| 🍭bufferCount | bufferCount 允许你在源 Observable 发出指定数量的值后,将这些值作为数组发出。 |
| 🍭bufferTime | bufferTime 允许你在一定时间间隔内收集源 Observable 发出的值,并在每个时间间隔结束时将收集到的值作为数组发出 |
| 🍭bufferToggle | bufferToggle 允许你通过打开和关闭缓冲区来控制何时发出缓冲区的值。它接受两个参数,一个用于打开缓冲区的 Observable,另一个用于关闭缓冲区的 Observable。 |
| 🍭bufferWhen | bufferWhen 允许你通过一个函数来动态地决定何时打开和关闭缓冲区。这个函数返回一个 Observable,当它发出信号时,缓冲区会发出当前收集到的值数组并重新开始缓冲。 |

7.2) 🍀window 系列

操作符 说明
🍭window window 操作符将数据流拆分成一系列窗口,每个窗口包含指定数量的项。它创建一个 Observable,该 Observable 发出这些窗口。
🍭windowCount windowCount 操作符与 window 类似,但是它是基于项的数量来创建窗口,而不是基于时间。
🍭windowTime windowTime 操作符创建一个 Observable,该 Observable 定期发出时间窗口,每个窗口包含在指定时间内发出的项。
🍭windowToggle windowToggle 操作符通过使用两个 Observables 控制窗口的开启和关闭。一个 Observable(开启 Observable)用于确定何时开始一个新窗口,另一个 Observable(关闭 Observable)用于确定何时关闭当前窗口。
🍭windowWhen windowWhen 操作符创建一个 Observable,该 Observable 在由另一个 Observable 提供的信号时开启新窗口。

7.3) 🍀switch 系列

操作符 说明
🍭switchMap switchMap 操作符用于将 Observable 的每个项映射为一个新的 Observable,然后仅发出最新映射产生的 Observable 的项,而忽略之前的映射。
🍭switchMapTo switchMapTo 操作符与 switchMap 类似,但它将每个源项映射为一个固定的 Observable(而不是基于源项的映射函数),然后只发出这个固定 Observable 的项。
🍭switchScan switchScan 操作符是 scanswitchMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 Observable。然后,它会取消订阅先前的 Observable(如果有的话),并订阅新的 Observable。这个操作符通常用于处理状态的累积和切换。

7.4) 🍀merge 系列

操作符 说明
🍭mergeMap mergeMap 操作符用于将每个源项映射为一个 Observable,然后将这些 Observables 并行合并成一个 Observable。它可以处理多个 Observable 的同时发射,并不会取消之前的 Observables。
🍭mergeMapTo mergeMapTo 操作符与 mergeMap 类似,但它将每个源项映射为一个固定的 Observable(而不是基于源项的映射函数),然后将这些 Observables 并行合并成一个 Observable。
🍭mergeScan mergeScan 操作符是 scanmergeMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 Observable。然后,它会将这些 Observables 并行合并成一个 Observable。

7.5) 🍀concat 系列

操作符 说明 观看视频
🍭concatMap concatMap 操作符用于将每个源项映射为一个 Observable,然后按顺序连接这些 Observables,一个接一个地发出它们的项。它确保前一个 Observable 完成后,才会订阅和发出下一个 Observable。
🍭concatMapTo concatMapTo 操作符与 concatMap 类似,但它将每个源项映射为一个固定的 Observable(而不是基于源项的映射函数),然后按顺序连接这些 Observables。

7.6) 🍀exhaust 系列

操作符 说明
🍭exhaust exhaust 操作符用于防止并发 Observable 的订阅。如果当前存在活跃的 Observable(第一个 Observable 还未完成),则会忽略后续的 Observable,直到第一个 Observable 完成。
🍭exhaustMap exhaustMap 操作符是 exhaust 的映射版本。它将每个源项映射为一个 Observable,然后只有当当前没有活跃的 Observable 时才会订阅和发出该 Observable。如果当前有活跃的 Observable,它会忽略新的 Observable。这个操作符通常用于确保在某个条件下只处理一个 Observable,而忽略其他触发条件。

7.7) 🍀map 系列

操作符 说明
🍭map map 操作符用于映射 Observable 中的每个项。你可以提供一个函数,该函数将每个源项映射为一个新的项,并在新的 Observable 中发出。
🍭mapTo mapTo 操作符将 Observable 中的每个项映射为一个固定的值。不像 map 需要一个函数进行映射,mapTo 直接指定一个值,然后在新的 Observable 中发出该值。

7.8)🍀merge 系列

操作符 说明
🍭mergeMap mergeMap 操作符用于将每个源项映射为一个 Observable,然后将这些 Observables 并行合并成一个 Observable。它可以处理多个 Observable 的同时发射,并不会取消之前的 Observables。
🍭mergeMapTo mergeMapTo 操作符与 mergeMap 类似,但它将每个源项映射为一个固定的 Observable(而不是基于源项的映射函数),然后将这些 Observables 并行合并成一个 Observable。
🍭mergeScan mergeScan 操作符是 scanmergeMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 Observable。然后,它会将这些 Observables 并行合并成一个 Observable。

7.9)🍀其他

操作符 说明 观看视频
🍭expand expand 操作符递归地将每个源项映射为一个 Observable,并在新的 Observable 中继续应用同样的映射函数。这样就形成了一个递归的数据流,直到满足某个条件为止。
🍭groupBy groupBy 操作符将源 Observable 中的项按照某个标准进行分组,每个分组形成一个新的 Observable。它创建一个 Observable,该 Observable 发出包含分组信息的 GroupedObservable 对象。
🍭pairwise pairwise 操作符将源 Observable 中相邻的两个项组合成一个二元组,然后发出这个二元组。
🍭partition partition 操作符将源 Observable 拆分为两个 Observables,根据提供的条件函数决定每个项属于哪个 Observables。
🍭pluck pluck 操作符用于提取 Observable 中每个项的指定属性的值,并将这些值发出。
🍭scan scan 操作符在源 Observable 发出项时递归地应用一个累加器函数,并发出累加的结果。它类似于 Array.prototype.reduce

八、过滤类型操作符

✅过滤类型操作符一共有 25 个操作符。

8.1)🍀audit

操作符 说明
🍭audit audit 用于在 Observable 流中定期采样一个辅助 Observable,并将该时刻的最新数据传递给下游。这有助于过滤掉高频产生值的情况,只保留在采样时刻最新的值。
🍭auditTime auditTime 用于在 Observable 流中定期采样值,并将最新的值传递给下游。与 audit 操作符类似,不同之处在于 auditTime 会定期固定时间间隔内采样值。

8.2) 🍀debounce

操作符 说明
🍭debounce debounce 用于限制在一定时间内发生的事件数量,确保只有在指定的时间间隔内没有新事件发生时,才会将最后一个事件传递给观察者。
🍭debounceTime debounceTime 作用是在指定的时间间隔内,只发出最后一次事件,忽略在这段时间内发生的其他事件。这对于处理频繁触发的事件,如用户输入、滚动等,可以有效地减少处理的次数,提高性能。

8.3) 🍀distinct

操作符 说明
🍭distinct distinct 操作符用于过滤掉源 Observable 中重复的元素,只保留首次出现的元素。
🍭distinctUntilChanged distinctUntilChanged 是 RxJS 中的一个操作符,它用于确保 Observable 连续发出的值不重复。它会过滤掉与前一个值相同的连续重复值,只发出发生变化的值。与 distinct 不同的是,distinctUntilChanged 只关心前后两个值是否相同,而不考虑整个 Observable 中的唯一性。
🍭distinctUntilKeyChanged 返回一个 Observable,它发出由源 Observable 发出的所有项目,这些项目与前一个项目相比是不同的,使用通过使用提供的键访问的属性来检查这两个项目是否不同。

8.4) 🍀first-last

操作符 说明
🍭first first 操作符用于从源 Observable 中获取满足条件的第一个元素,并在获取到第一个元素后立即完成 Observable。如果没有满足条件的元素,可以选择提供一个默认值,或者抛出一个错误。
🍭last last 操作符用于从源 Observable 中获取满足条件的最后一个元素,并在获取到最后一个元素后立即完成 Observable。如果没有满足条件的元素,可以选择提供一个默认值,或者抛出一个错误。

8.5)🍀sample 系列

操作符 说明
🍭simple sample 操作符用于定期从源 Observable 中发出一个值,该值是在另一个 Observable(称为采样 Observable)发出值的时候捕获的。这有助于控制事件流的频率。
🍭simpleTime sampleTime 是指定的时间间隔定期对源 observable 进行采样,并发出最近的值

8.6)🍀skip 系列

操作符 说明
🍭skip skip 用于跳过 Observable 中指定数量的值的操作符。它会忽略源 Observable 发出的前几个值,只关注之后的值。
🍭skipLast skipLast 用于跳过 Observable 中指定数量的最后几个值的操作符。它与 skip 操作符相似,但是是跳过 Observable 的尾部值。
🍭skipUntil skipUntil 用于跳过 Observable 中的值,直到指定的另一个 Observable 发出值时才开始接收源 Observable 值的操作符。
🍭skipWhile skipWhile 用于跳过 Observable 中的值,直到某个条件不再满足时才开始接收源 Observable 值的操作符。

8.6)🍀take 系列

操作符 说明
🍭take take 操作符用于从源 Observable 中取得指定数量的值,然后完成 Observable。它是一种有限操作符,通常用于限制 Observable 发出的元素数量。
🍭takeLast takeLast 操作符用于从源 Observable 中取得指定数量的最后几个值,然后完成 Observable。这是一个有限操作符,通常用于获取 Observable 中的末尾元素。
🍭takeUntil takeUntil 操作符用于在另一个 Observable 发出值时,终止源 Observable。这是一种用于管理 Observable 生命周期的操作符。
🍭takeWhile takeWhile 操作符用于在满足特定条件的情况下,从源 Observable 中取得值,然后完成 Observable。这是一种有限操作符,它允许你根据条件来控制取值的过程。

8.7) 🍀throttle

操作符 说明
🍭throttle throttle 操作符用于在一段时间内只接收第一个值,然后忽略后续的值,以控制事件的触发频率。这对于处理用户输入、滚动事件等场景非常有用。
🍭throttleTime throttleTime 操作符是 RxJS 中用于限制事件流的触发频率的操作符。它会在指定的时间间隔内,只接收第一个值,然后忽略在该时间间隔内的所有其他值。

8.8) 🍀其他

操作符 说明 观看视频
🍭elementAt elementAt 操作符用于从源 Observable 中获取指定索引位置的元素,并将其作为单一元素的 Observable 发出。索引位置是从 0 开始计数的。
🍭ignoreElements ignoreElements 操作符用于忽略源 Observable 发出的所有元素,只关注 Observable 的终止状态(complete 或 error)。它通常用于处理只关心 Observable 是否完成的场景。
🍭single single 操作符用于在源 Observable 中,确保只有一个满足指定条件的元素,然后完成 Observable。如果满足条件的元素数量不是一个,single 操作符会抛出一个错误。

九、Join 操作符

Join 型操作符包含 7 个操作符

操作符 说明
🍭combineLatestAll 用于将多个 observable 的最新值组合成一个数组,并在任一 observable 发出新值时触发。
🍭concatAll 用于按顺序连接多个 observable
🍭exhaustAll 用于在一个 observable 处于活跃状态时,忽略其他 observable 的值,直到该 observable 完成。
🍭mergeAll 用于将多个 observable 的值合并成一个单一的 observable。
🍭switchAll 用于将高阶 observable 打平(降维)成一阶 observable,并只订阅最新的内部 observable。
🍭startWith 用于在 observable 发出值之前插入指定的起始值。
🍭withLatestFrom 用于将一个 observable 与其他 observables 的最新值合并,并在源 observable 发出值时触发。

十、错误处理操作符

✅错误型操作符包含 3 个操作符

10.1) 🍀retry 系列操作符

操作符 说明
🍭retry 操作符 retry 用于在Observable发生错误时进行重试。当Observable抛出错误时,retry将重新订阅原始Observable,从而给予它另一次执行的机会。
🍭retryWhen 操作符 retryWhen 允许你更灵活地控制何时进行重试。与retry不同,retryWhen接受一个函数作为参数,该函数返回一个新的Observable。当原始Observable发生错误时,retryWhen会调用这个函数,并且只有当这个新的Observable发出值时,它才会进行重试。(已经不推荐使用)

10.2) 🍀其他

操作符 说明 视频
🍭catchError catchError 是 RxJS 中的一个操作符,用于捕获 observable 中的错误,并提供一个备用的 observable 或值来处理错误。这个操作符通常用于处理 observable 中的异常情况。

十一、工具操作符

✅工具型操作符包含 12 个操作符

11.1) 🍀delay 系列

操作符 说明
🍭delay delay 操作符是 RxJS 中用于引入时间延迟的一种操作符。它的主要目的是推迟 observable 发出的数据,以便在一定的时间间隔之后再将数据传递给订阅者。
🍭delayWhen delayWhen 操作符是 RxJS 中用于引入动态延迟的操作符。它允许你根据每个值的情况动态地设置延迟时间,而不是像 delay 操作符那样使用固定的延迟时间。

11.2) 🍀materilize-dematerilize 系列

操作符 说明
🍭dematerilize dematerialize 操作符用于将源 observable 发出的 Notification 对象转换回它们原始的通知类型。通常,当使用 materialize 操作符将 observable 的通知转换为 Notification 对象后,可以使用 dematerialize 恢复原始的通知类型。
🍭materilize materialize 操作符用于将 observable 的每个通知(包括 next、error 和 complete)转换为一个特殊的 Notification 对象。这个对象包含了原始通知的类型以及对应的值或错误信息。

11.3) 🍀observeOn 和 subscribeOn 系列

操作符 说明
🍭observeOn observeOn 操作符是 RxJS 中用于控制 observable 在哪个调度器上执行的操作符。它允许你指定在哪个上下文中订阅和观察 observable,以及处理它们发出的数据。
🍭subscribeOn subscribeOn 操作符是 RxJS 中用于指定 observable 在哪个调度器上进行订阅的操作符。它影响 observable 的订阅阶段,而不是数据发出阶段。

11.4) 🍀time 系列

操作符 说明
🍭timeInterval timeInterval 操作符是 RxJS 中的一个用于测量两个连续数据发出之间的时间间隔的操作符。它会将 observable 发出的每个数据包装成一个对象,该对象包含原始数据和与上一个数据发出之间的时间间隔。
🍭timestamp timestamp 操作符是 RxJS 中的一个用于给每个发出的数据项附加时间戳的操作符。它将 observable 发出的每个数据包装成一个对象,该对象包含原始数据和该数据的时间戳。
🍭timeout timeout 操作符是 RxJS 中的一个用于设置超时的操作符。它可以用来限制 observable 在规定时间内完成,否则会引发超时错误。
🍭timeoutWith timeoutWith 操作符是 RxJS 中的一个用于处理超时情况并提供备用 observable 的操作符。它允许你在 observable 超时时切换到另一个备用的 observable。

11.5) 🍀其它

操作符 说明 观看视频
🍭tap tap 用于在Observable的生命周期中拦截并执行一些额外的操作,而不会对Observable的值产生影响。它对于调试、记录日志或执行任何不会改变Observable的操作非常有用。
🍭toArray toArray 用于将 observable 发出的所有数据收集到一个数组中的操作符。它会等待 observable 完成(发出 complete 通知)后,将所有的 next 通知的值组合成一个数组,然后发出这个数组.

十二、条件和布尔类型操作符

✅条件和布尔型操作符包含 5 个操作符

12.1) 🍀find 系列

操作符 说明
🍭find find 用于在 observable 中找到第一个满足条件的数据项的操作符。它会在找到满足条件的数据项后发出该项,并完成 observable。
🍭findIndex findIndex 用于找到第一个满足条件的数据项的索引的操作符。它会在找到满足条件的数据项后发出该项的索引,并完成 observable。

12.2) 🍀其他

操作符 说明 视频
🍭defaultIfEmpty defaultIfEmpty 用于在 observable 为空时提供默认值的操作符。它会检查 observable 是否发出了任何数据,如果没有,则发出指定的默认值。
🍭every every 用于判断 observable 中所有数据项是否都满足指定条件的操作符。它会在 observable 完成时发出一个布尔值,表示所有数据项是否都满足条件。
🍭isEmpty isEmpty 用于检查 observable 是否为空的操作符。它会在 observable 完成时发出一个布尔值,表示 observable 是否为空(没有发出任何数据项)。

十三、数学和聚合操作符

✅数学和聚合操作符符包含 4 个操作符

操作符 说明 视频
🍭count count 操作符用于统计源 Observable 发出的项的数量,并在完成时发出该数量。它返回一个新的 Observable,该 Observable 只发出一个项,即源 Observable 发出的项的数量。
🍭max max 操作符用于找到源 Observable 发出的项中的最大值,并在完成时发出该最大值。它返回一个新的 Observable,该 Observable 只发出一个项,即源 Observable 中的最大值。
🍭min min 操作符用于找到源 Observable 发出的项中的最小值,并在完成时发出该最小值。它返回一个新的 Observable,该 Observable 只发出一个项,即源 Observable 中的最小值。
🍭reduce reduce 操作符用于递归地应用一个累加器函数来处理源 Observable 发出的每个项,并在完成时发出最终的累加结果。它返回一个新的 Observable,该 Observable 只发出一项,即最终的累加结果。

十四、主题

操作符 说明
🍭Subject 一种同时充当观察者和可观察对象的特殊类型。它是热 Observable,开始时不会发射值,而是在有观察者订阅后才开始发射值。
🍭BehaviorSubject 在创建时需要初始值,会记住最新的值,并在有新的观察者订阅时立即将这个值推送给观察者。
🍭ReplySubject 会记住 Observable 发射的所有值,并在有新的观察者订阅时将这些值全部发送给观察者。
🍭AysncSubject 只有当 Observable 完结时才会将最后一个值发送给观察者。
🍭Void Subject 无值的 Subject,即不传递任何值给观察者。

十五、调度

操作符 说明
🍭null 过不传递任何调度程序,通知将同步且递归地传递。将此用于恒定时间运算或尾递归运算。
🍭queueScheduler queueScheduler 是 RxJS 中的一个调度器,用于在当前任务队列结束时调度任务。它会按照顺序执行任务,确保任务按照添加的顺序执行。
🍭asapScheduler asapScheduler 是 RxJS 中的调度器之一,表示尽快调度任务,但会优先于 queueScheduler 执行。
🍭asyncScheduler asyncScheduler 是 RxJS 中的调度器,它使用 setTimeoutsetInterval 来安排任务的执行。它提供了异步调度的能力。
🍭animationFrameScheduler animationFrameScheduler 是 RxJS 中专门用于与浏览器的 requestAnimationFrame 配合的调度器。它可用于实现与动画相关的任务调度。

十六、多播

16.1)🍀v8 版本

ConnectableObservable 对象在 v8 版本中将被废弃,推荐使用 connectable 进行链接。refCount 推荐使用 share 操作符。

16.2)🍀新多播 API

操作符 说明
🍭connectable 创建一个可观察对象,一旦connect()调用它,就会进行多播。
🍭connect 通过在一个函数中多播源来创建一个Observable,该函数允许开发人员在连接之前定义多播的用法。
🍭share 返回一个新的Observable,它多播(共享)原始Observable。只要至少有一个订阅者,这个Observable就会被订阅并发出数据。当所有订阅者都取消订阅时,它将取消订阅源Observable。因为Observable是多播的,所以它使流 hot 。这是 multicast(() => new Subject()), refCount() 的别名。
🍭shareReply 共享源和重播订阅时指定数量的排放。

16.3)🍀多播适用场景

多播通常用于处理计算成本高昂的操作,如网络请求或定时器。

16.4)🍀多播与主题的不同

  • 多播用于在多个订阅者之间共享同一组数据,以提高性能。
  • 主题用于手动推送值给订阅者,每个订阅者可以接收到不同的值。

16.5)🍀多播基础对象转换

  • 🍭ConnectableObservable -> connectable
  • 🍭refCount -> share

16.6)🍀多播

  • 🍭multicast -> connectable
  • 🍭multicast + subject -> connectable(resetOnDisconnect) + subject
  • 🍭multicast + subject + refCount -> share
  • 🍭multicast 和选择器 -> connect

16.7)🍀publish 转换

  • 🍭publish -> connectable(resetOnDisconnect/connector)
  • 🍭publish + refCount -> share
  • 🍭publish 和选择器 -> connect

16.8)🍀publishBehavior 转换

  • 🍭publishBehavior -> connectable + BehaviorSubject
  • 🍭publishBehavior + refCount -> share + BehaviorSubject

16.9)🍀publishLast 转换

  • 🍭publishLast -> connectable + AsyncSubject
  • 🍭publishLast + refCount -> share + AsyncSubject

16.10)🍀publishReply 转换

  • 🍭publishReplay -> connectable + ReplaySubject
  • 🍭publishReplay + refCount -> share + ReplaySubject
  • 🍭publishReplay + 选择器 -> connect + ReplaySubject

十七、测试

17.1)🍀简介 Marble Testing

Marble Testing 使用一种被称为 "marbles" 的可视化语言,它可以帮助开发者更直观地理解和测试 Observable 的行为。

17.2)🍀Marble Diagram

用于展示 Observables 在时间轴上的行为,在 Diagram 中时间从左向右逐渐增加

17.3)🍀Marble 语法和时间线推进语法

字符 含义
' ' 水平空格,被忽略,可用于垂直对齐多个 Marble Diagrams
'-' 表示虚拟时间的一帧(frame)
`[0-9]+[ms s
`' '`
'#' 表示 Observable 发生错误,即 producer 发送 error() 信号
[a-z0-9] 表示 producer 发送的值,通过 next() 发射
'()' 表示同一帧中的多个事件,用于同步地发送多个值或完成/错误信号。例如,(abc) 表示在同一帧中发射值 a、b、c,然后虚拟时间向前推进 (abc).length 个 frames
'^' 订阅点,用于标示测试时 hot observables 的被订阅点。这是 hot observable 的 "zero frame",每个 ^ 之前的 frame 都是负值。

示例表格:

markdown 复制代码
| 时间 (Time) | -   | 0   | 1   | 2   | 3   | 4   | 5   |
|-------------|-----|-----|-----|-----|-----|-----|-----|
| Observable  | -   | a   | b   | c   | -   | d   | \|  |
|             | ' ' | '-' | '-' | '-' | ' ' | '-' | '|' |

17.4)🍀测试工具与示例

ts 复制代码
import { TestScheduler } from 'rxjs/testing';
import { throttleTime } from 'rxjs';

const testScheduler = new TestScheduler((actual, expected) => {
  expect(actual).deep.equal(expected);
});

it('generates the stream correctly', () => {
  testScheduler.run((helpers) => {
    const { cold, time, expectObservable, expectSubscriptions } = helpers;
    const e1 = cold(' -a--b--c---|');
    const e1subs = '  ^----------!';
    const t = time('   ---|       '); // t = 3
    const expected = '-a-----c---|';

    expectObservable(e1.pipe(throttleTime(t))).toBe(expected);
    expectSubscriptions(e1.subscriptions).toBe(e1subs);
  });
});

TestScheduler 构造器得到一个实例,示例中需要可以进行断言测试,可以用 chai、jest或者vitest等其他断言库提供。

testScheduler 实例,提供了 run 方法,在 run 的函数参数,函数参数包含 helpers 包含测试常用的对象:

  • cold
  • time
  • expectObservable
  • ...

等等api, 此时根据自己的需求使用。

十八、小结

本文旨在加强对 RxJS 基础认知和知识结构的构建,本文试图磨平 RxJS 基础到进阶的难度。基本包含 RxJS 的所有基础内容。本文结合文字,图片,思维导图,短视频视图全方位讲解并熟悉 RxJS, 但想要熟悉 RxJS 任然需要大量的练习。本文是2023年9月开始认真做 RxJS 和实战 RxJS 一次基础的总结,后面随着对源码的理解加深和对使用场景的加深,以及其他能力的加深,出第二个版本。希望能够帮助到大家。

相关推荐
m0_748250746 分钟前
高性能Web网关:OpenResty 基础讲解
前端·openresty
前端没钱32 分钟前
从 Vue 迈向 React:平滑过渡与关键注意点全解析
前端·vue.js·react.js
NoneCoder36 分钟前
CSS系列(29)-- Scroll Snap详解
前端·css
无言非影40 分钟前
vtie项目中使用到了TailwindCSS,如何打包成一个单独的CSS文件(优化、压缩)
前端·css
.生产的驴1 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
我曾经是个程序员1 小时前
鸿蒙学习记录
开发语言·前端·javascript
顽疲1 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
机器之心1 小时前
AAAI 2025|时间序列演进也是种扩散过程?基于移动自回归的时序扩散预测模型
人工智能·后端
羊小猪~~1 小时前
前端入门之VUE--ajax、vuex、router,最后的前端总结
前端·javascript·css·vue.js·vscode·ajax·html5
摸鱼了2 小时前
🚀 从零开始搭建 Vue 3+Vite+TypeScript+Pinia+Vue Router+SCSS+StyleLint+CommitLint+...项目
前端·vue.js