RxJS的常见错误
作为开发人员,我处于RxJS观点的中级水平。我的经验是使用Angular的RxJava和RxJS。在此博客中,我已经发布了一个 RxJs核心上的速成课程.

今天,当我们使用RxJS时,我将分享一些常见的错误。作为开发人员,本文将对您有所帮助。让’开始本教程。
取消订阅的使用
我和许多其他人就该主题进行了详尽的讨论,但这仍然是我通常看到的最常见的错误—即不取消订阅流 完全没有.
这会产生各种后果,例如:
- 导致内存泄漏
- 导致不必要的回调
- 可能会导致您的应用程序出现严重错误
取消订阅Observable的最好,最优雅的方法是使用在组件销毁时发出值的主题。
另外,您可以通过订阅在组件上维护类属性,并在组件被销毁时取消订阅。
It’s pretty important, 不要’t forget.
忽略初始值
这在Angular表单中很常见。假设您订阅了一条流,期望获得价值—但你永远得不到一个。那怎么可能?
好— sometimes it’是由于未使用初始值初始化流,并且从未调度事件。
这里’是Angular的常见情况’s forms:
1 2 3 4 5 6 |
const 名称 = 新 表格控件(吉安卡洛(Giancarlo)); const 表格组 = 新 表格组({ 名称 }); const 价值变化$ = 表格组.价值变化; 价值变化.订阅((值) => { // 做点什么 }); |
除非用户更改 名称
以某种方式使用FormControl,将永远不会调用该回调。但—我们确实希望订阅使用的初始值发出 表格组
(很多人希望它会这样做)。
在这种情况下,我们需要使用运算符来推送初始值 从...开始
:
1 2 3 4 5 6 |
const 价值变化$ = 表格组.价值变化.管( 从...开始(表格组.值) ); 价值变化.订阅((值) => { // 做点什么 }); |
在这种情况下,我们将使用表单的初始值接收到一个发射,并且此后发射所有更改。
选择错误的运算符
那里有很多运营商—虽然你当然不’不需要全部学习它们,您需要确保您了解所使用的每个细节。
细微的差异可能会产生重大后果。
示例:mergeMap与switchMap
最常用的运算符之一是 mergeMap
。该运算符使您可以展平内部的Observable并为每个事件维护许多活动流:在某些情况下这很好,而在其他情况下不是很理想。
在许多情况下,您可能只想维护1个活动订阅。例如,如果您有一个事件,该事件的事件调用HTTP端点,则可能要取消传出的请求,而只调用最新的请求:在这种情况下,您可以’会更好 switchMap
.
如果你’re not careful, mergeMap
可能会导致重复和不必要的订阅,而 switchMap
can lead to 比赛条件。最终,两者都可能导致错误和代码故障。

This is one example of the many, sometimes tiny, differences that make RxJS 经营者.
正如我上面所说—您不需要了解每个Rx运算符。但是,您确实需要了解您所拥有的产品的细微特点。’重新使用并与其他同类产品进行比较,以了解哪种类型适合您的情况。
您应该注意的其他显着差异:
- 邮编vs叉子加入vs组合最新vs种族
- 合并与合并
- 计时器与间隔
- 永不虚无
- 来自
- 缓冲区与窗口
Note: 如果你 want any other comparison with detail then comment us below.
使用错误的主题类型
不要犯的另一个重要错误是不要为任务选择错误的主题类型。
主题是Observable的一种特殊类型,它使您可以在流中推送值,也可以通过订阅它来检索它们。虽然正常 Subject
可能涵盖大多数情况,您应该注意一些细微的差异。
后期订阅者
一种常见的情况是您的主题在观察者订阅其更改之前发出事件。如果你’期望您的订户收到数据,您’再走运:它赢了’t.
在这种情况下,您应该选择 ReplaySubject
,它可以将收到的所有事件重播给后期订阅者。当您只想将最新值保留在内存中时(通过定义其缓冲区大小可以执行此操作),它也特别有用。
另一种选择是 BehaviorSubject
—而是需要一个值才能定义。
订阅回调中的命令式逻辑
RxJ的最大优点之一是,组合运算符并重用其逻辑是一种构建可重用代码位的非常好(且简便)的方法。
一旦订阅了Observable,编写Rx代码的许多好处就结束了:我们在订阅回调中编写的逻辑不是Rx-land,而是’是我们代码中FRP结尾的开始。
我并不是说您永远都不要订阅,但我的建议是使订阅回调中的逻辑尽可能小—并尽可能避免直接订阅(例如,使用Angular async
pipe).
在订阅中使用逻辑的缺点是什么?
有限的可重用性
RxJS流是可管道的,这意味着它们可以组合和扩展,因此可以重用。
每当您订阅并在订阅中执行逻辑时,您就会带走一些本可以卸载给Rx运算符的逻辑:
1 2 3 4 5 6 7 8 9 10 11 |
const 所有项目$ = 这个.服务.项目$.管( 过滤(布尔型) ); const 不要eItems$ = 所有项目$.管( 地图(项目 => 项目.过滤(项目 => 项目.不要e)), ); const numberOfRemainingItems$ = 结合最新( [所有项目$, 不要eItems$] ).管( 地图(([项目, 不要eItems]) => 项目 - 不要eItems), ); |
如您所见,创建中间流或将逻辑卸载到单独的运算符上,是在整个应用程序中重用逻辑的绝佳方法。
根据经验:
- 无需检查订阅中的值是否真实,您可以轻松地与运营商联系
过滤器(布尔)
- 不要’转换订阅中的数据
- 副作用:例如,显示/隐藏加载图标可以通过
tap
or/and thefinalize
operators
较少声明
让’请参见命令式和声明式代码段之间的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
类 用户sDashboardComponent { 使用者: 用户[]; 活性Users: []; 被禁止Users: []; 建设者(私人的 服务: 用户sService) { 这个.服务.使用者$.订阅(使用者 => { 如果 (使用者) { 这个.使用者 = 使用者; 这个.活性Users = 使用者.过滤(用户 => 用户.活性); 这个.被禁止Users = 使用者.过滤(用户 => 用户.被禁止); } }); } } |
现在,让’s转换以上声明性流:
1 2 3 4 5 6 7 8 9 10 11 12 |
类 用户sDashboardComponent { 使用者$ = 这个.服务.使用者$.管( 过滤(布尔型) ); 活性Users$ = 这个.使用者$.管( 地图(使用者 => 使用者.过滤(用户 => 用户.活性)), ); 被禁止Users$ = 这个.使用者$.管( 地图(使用者 => 使用者.过滤(用户 => 用户.被禁止)), ); 建设者(私人的 服务: 用户sService) {} } |
话虽如此,唐’别忘了订阅,否则,您的可观察物将永远不会发出。
最后的话
Rx是一个非常出色的库和工具,可以帮助您轻松处理应用程序的复杂异步方面。它’也很大,并且经常被误解。
确保遵循上述建议,至少可以确保您’重新处理错误或您花费数小时试图修复的错误的极为常见的原因。
综上所述
- 总是退订
- 唐’如果期望一个初始值,则省略
- Learn well the 经营者 that you’re using. Small differences 可导致 big mistakes.
- 您应该使用正确的主题类型。
- 在流中尽可能声明性地编写逻辑。同样,将逻辑与自定义运算符或中间流一起重用。
如果您需要任何澄清,或者您认为不清楚或错误的地方,请发表评论!

