带有latestfrom操作符的RxJs

我们的每周RxJs操作符withLatestFrom它是一个名字能说明一切的操作符的罕见例子。

这是大理石图withLatestFrom

这个运算符取两个或多个可观察对象然后把它们变成一个可观察对象的时候,就会产生一个新值source Observable会释放一些新的东西

这里需要注意的重要一点是,只有一个Observable在输出Observable中触发更新。结果,withLatestFrom当您希望用户操作触发用户界面中的更新时(考虑数据表过滤器、相互连接的下拉列表等),是一个很好的选择。

你可以看到现场直播代码示例(包括解释思维过程的注释),两个相互依赖的下拉列表。第一个下拉列表中的选择会影响第二个下拉列表中显示的值(选择一个大洲会过滤掉第二个下拉列表中显示的国家:

如果你想深入了解,我有这个关于使用的完整教程withLatestFrom与其他操作符一起在组件中实现动态过滤

更多的RxJs内容,我的2小时RxJS工作坊从ng-conf 2022现在可以在Youtube上免费观看!

RxJs的点击操作符

利用运算符是最简单的一种RxJs操作符,因为它不会改变进入你的可观察对象的数据:

为什么我们需要一个什么都不做的函数呢?我们看到了第一个非常重要的例子,使我们能够使用异步早些时候。

至少有三个重要的用例是:

  • 调试复杂的RxJs场景使用console.log(如上图所示)
  • 注册副作用随着数据的变化(这就是我们在异步管道场景中所做的)
  • 用于完成内部可观察对象(当您将多个可观察对象组合到一个订阅时)

简而言之,利用是一种方法监视可观察流内部发生了什么。任何时候你想要提取一些数据/调试/看看Observable中发生了什么,利用是最简单的答案。

你可以在我的教程中找到这三个场景的例子:使用的3个原因利用操作符

ngrxLet:异步管道的更好版本

昨天,我们提到如何异步管材可配合使用* ngIf* ngFor在我们的模板中声明一个局部变量,允许我们使用相同的数据有多个表达式:

              
              
<divngIf"user$ | async as user"><p>名字:{{用户。firstName}}p><p>姓:{{用户。lastName}}p>div>
代码语言:HTML、XMLxml

虽然上面的代码运行得很好,但添加其他代码并不总是很方便* ngIf* ngFor在我们的模板中。异步管道的另一个缺点是它不让我们知道是否可观测的发生错误或成功完成。

这就是ngrxLet指令可以解决问题,因为它用简单的语法解决了上述所有缺点。我们之前的例子变成:

              
<divngrxLet"user$ as user"><p>名字:{{用户。firstName}}p><p>姓:{{用户。lastName}}p>div>
代码语言:HTML、XMLxml

如果我们想要获得任何错误或可观察对象的完成状态,我们可以通过暴露的更多局部变量来实现ngrxLet

              
<divngrxLet“user$ as user;误差为e;完整为c">
代码语言:HTML、XMLxml

你可以找到完整的工作示例ngrxLet可以使用NPM作为依赖项安装(NPM install @ngrx/component),重要的是要注意它不是全部ngrx状态管理库,只是它的一个很小的子集,所以使用该指令不需要使用其他任何东西ngrx

如果你想深入了解,这里有一个稍微扩展版本的教程链接,其中有更多信息:ngrxLet -一个更好的异步管道版本

异步管道语法技巧

昨天,我们写过如何使用异步管道自动订阅和取消订阅从我们的观测数据。

当我教授这个话题时,人们通常至少有以下两种反对意见之一:

如果我还需要订阅的数据在我的Typescript代码?

首先,使用异步pipe似乎只允许您访问HTML模板中的数据。但事实并非如此,因为你仍然可以使用tap操作符来“监视”你的可观察对象,并从中获取数据。例如(完整例子):

              
.name$ = nameService.getName()。管(丝锥(的名字= >.name = name));
代码语言:打印稿打印稿

然后在HTML模板中:

              
<p>async管道的名称:{{Name $ | async}}p>
代码语言:HTML、XMLxml

如果我需要从订阅中的对象中读取多个属性怎么办?

另一种说法是,你不想以这样的方式结束:

              
<p>名字:{{(用户$ | async)?。firstName}}p><p>姓氏:{{(用户$ | async)?。lastName}}p>
代码语言:HTML、XMLxml

上面的代码很难阅读,每个属性都需要一个订阅。这本身就是一场灾难,因为每个订阅都可能触发来自服务器的相同数据的HTTP请求!

相反,您可以这样做,只使用一个订阅,将结果存储在一个局部变量中,然后在数据可用时呈现数据。此技术适用于任何结构指令,例如* ngIf* ngFor

              
<divngIf"user$ | async as user"><p>名字:{{用户。firstName}}p><p>姓:{{用户。lastName}}p>div>
代码语言:HTML、XMLxml

如果通过添加元素来适应订阅来更改DOM结构让您感到困扰,那么您可以使用ng-template相反,尽管这里的语法也可能有点令人不安:

              
<ng-templatengIf] ="user$ | async"让用户><p>名字:{{用户。firstName}}p><p>姓:{{用户。lastName}}p>ng-template>
代码语言:HTML、XMLxml

好了,今天就到这里吧。明天,我们将看到我们如何做得比现在更好。

如何避免RxJs可观察对象的内存泄漏?

在大型Angular应用程序中,最容易陷入麻烦的方法是不取消订阅可观察对象会造成内存泄漏.虽然有不同的技术自动取消订阅可观察对象,一种方法更简洁、优雅,而且总体上是最防错的。

这个技巧就是使用异步从Angular框架。

为什么异步管这么厉害的工具?

  1. 首先,它自动订阅可观察对象,因此我们不再需要调用.subscribe ()
  2. 它返回来自该可观察对象的数据,在我们的组件需要显示最新数据时触发Angular的更改检测。
  3. 最后,当我们的组件被销毁时,它会自动从可观察对象中取消订阅。

所有这一切都只需要6个字符!(好吧,如果你想计算空白,可能会多一点):

              
<div>{{myObservable | async}}div>
代码语言:HTML、XMLxml

异步如果我们不使用Pipe,它的工作方式与我们编写的代码完全相同(因此会反复重复,使代码库更大,从而使代码更慢)。

检查它的源代码在这里,您将看到它所做的一切都是实现ngOnDestroy取消订阅我们的可观察对象。

没有任何好的理由不使用异步管道,如果您认为您有一些理由,请继续关注我们的下一条消息,因为我们将介绍一些关于使用该管道的很好的提示和技巧。

RxJs组合最新运算符

combineLatest有一个说明一切的名字:操作符将两个或多个可观察对象的最新值组合成一个可观察对象。

这张大理石图完美地说明了这种行为(点击图片可以访问交互式版本):

该操作符有几种可能的用例。最常见的用法是通过组合不同的源来过滤信息,如下图所示RxJs和Angular表单的动态过滤教程,它实现了相当于自动补全文本输入的功能,每当用户输入新字符时,就会显示新的建议。

我们得到了什么combineLatest由组合的可观察对象发出的所有最新值组成的数组。例如,如果我们订阅组合最新(obs1, obs2, obs3),我们得到的数据是一个数组,包含[lastValueFromObs1, lastValueFromObs2, lastValueFromObs3].数组中数据的顺序与传递可观察对象的顺序相匹配combineLatest,该数组的值将再次发射,每当其中一个可观察对象再次发射。

一个常见的陷阱combineLatest操作符是否等待所有可观察的源至少发出一个值才返回某个值,因此将它与startWith操作符,如这个例子来自我们之前的教程

注意:操作符将被重命名为combineLatestWith在RxJs 8+

RxJs的switchMap操作符

Angular应用中常见的一个错误是用以下方式嵌套可观察订阅:

              
observable1.subscribe (数据= >{observable2.subscribe (otherData= >//对otherData执行一些操作});});
代码语言:JavaScriptjavascript

不推荐使用上述语法,因为它很难阅读,并且可能导致微妙的错误和意想不到的副作用。例如,这种语法很难正确地取消所有这些可观察对象的订阅。

同样,如果observable1如果在短时间内触发多次,则可能需要取消以前的订阅observable2并根据接收到的新数据开始一个新的observable1.上面的代码没有做任何这些工作。

解决方案:使用RxJsswitchMap这样的运算符:

              
observable1.pipe (数据= >{switchMap (数据= >observable2) .subscribe (otherData= >//对otherData执行一些操作});
代码语言:JavaScriptjavascript

switchMapOperator执行以下所有操作:

  • 自动取消和取消订阅observable2如果observable1产生一个新值。
  • 自动取消订阅observable2如果我们取消订阅observable1
  • 确保observable1而且observable2依次发生,一个接一个。

下面的大理石图很好地说明了什么switchMap:

如果你不吸毒的话switchMap但是,请在代码中查找对的嵌套调用.subscribe (),然后开始用switchMap操作符,以防止内存泄漏和错误,并使您的代码更具可读性。

这里有一个链接一个使用定时器每30秒发出一次HTTP请求的例子获取更新的数据。使用将计时器数据转换为API调用switchMap在示例的第37行。