一、简介
从 2023 年 NestJS 的学习与实践中发现,RxJS 在 NestJS gRPC 微服务中扮演重要角色,gRPC 的 proto 文件生成 TS 类型文件式,使用可观察对象,而不是 Promise。
面对 NestJS 和 Angular 系列,如果对 RxJS 不熟悉,就像多年前都端开发者不熟悉 webpack 一样。
多年以后回顾 webpack, 学习 RxJS 的场景就跟以前简直一模一样。
为了更好的学习并全面的掌握 RxJS, 本文以 RxJS 基础为核心用有文字图片、配合视频方式讲解,希望能够帮助到大家。
RxJS 是一个函数式的响应式可观察对象编程库。
- 💌RxJS 官方网站
- 💞RxJS Github 代码托管仓库
- 🎁RxJS npm 包管理工具
二、可观察对象基础
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 操作符是 scan 和 switchMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 Observable。然后,它会取消订阅先前的 Observable(如果有的话),并订阅新的 Observable。这个操作符通常用于处理状态的累积和切换。 |
7.4) 🍀merge 系列
操作符 | 说明 |
---|---|
🍭mergeMap |
mergeMap 操作符用于将每个源项映射为一个 Observable,然后将这些 Observables 并行合并成一个 Observable。它可以处理多个 Observable 的同时发射,并不会取消之前的 Observables。 |
🍭mergeMapTo |
mergeMapTo 操作符与 mergeMap 类似,但它将每个源项映射为一个固定的 Observable(而不是基于源项的映射函数),然后将这些 Observables 并行合并成一个 Observable。 |
🍭mergeScan |
mergeScan 操作符是 scan 和 mergeMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 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 操作符是 scan 和 mergeMap 的结合。它接受一个累加器函数和一个映射函数,将每个源项应用于累加器函数,得到一个中间累加值,然后将中间累加值传递给映射函数,映射函数返回一个 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 中的调度器,它使用 setTimeout 或 setInterval 来安排任务的执行。它提供了异步调度的能力。 |
🍭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 一次基础的总结,后面随着对源码的理解加深和对使用场景的加深,以及其他能力的加深,出第二个版本。希望能够帮助到大家。