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 一次基础的总结,后面随着对源码的理解加深和对使用场景的加深,以及其他能力的加深,出第二个版本。希望能够帮助到大家。

相关推荐
学习前端的小z5 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
XINGTECODE14 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
程序猿进阶19 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺24 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
彭世瑜29 分钟前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund40430 分钟前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish30 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小五Five31 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序31 分钟前
vue3 封装request请求
java·前端·typescript·vue
临枫54132 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript