布莱恩F爱
向一位来自Portlandyobet英雄联盟的谷歌开发专家学习Angular、Web技术和Node.js。
广告 ·ultimatecourses.com
用终极课程学习Angular的正确方法

Angular:别忘了退订()

不要忘记在Angular组件中使用OnDestroy生命周期钩子取消订阅。我们来看看:

  1. 为什么要退订
  2. 当你可能要退订的时候
  3. 你如何退订

2018年7月7日更新

我已经更新了这篇文章,以正确使用takeUntil ()操作员在takeWhile ()的方法。使用takeWhile ()只会在发出另一个通知后停止接收来自被观察源的通知。另一方面,使用takeUntil ()当我们调用时是否会立即停止接收来自可观察源的通知next ()在通知主体上。

2017年1月4日更新

我已经更新了这篇文章,包括使用takeWhile ()操作符是取消订阅Angular组件的更好策略。

更新2017年9月13日

我已经更新了这篇文章,包括使用takeUntil ()操作符作为Angular组件中取消订阅的另一种策略。

为什么?

Reactive-Extensions为JavaScript(或RxJS)向Angular引入了可观察的概念。如果你一直在使用Angular的第一版,那么你很可能会习惯使用承诺。而且,虽然你可能认为一个可观察对象就像一个承诺,你可能会惊讶(就像我一样),了解到他们实际上是非常不同的。

首先,承诺是迫切的,并立即执行。可观察对象不是急于执行的,仅在订阅时执行。

第二,承诺是不同步的。可观察对象可以是同步的,也可以是异步的。

第三,promise期望只返回一个值(像函数一样)。可观察对象可以返回零、一个或多个(无限)值。

让我开门见山。订阅创建时,我们订阅()一个可观察到的。而且重要的是,我们要取消在Angular组件中创建的订阅,以避免内存泄漏。

AsyncPipe

在我们继续前进之前;如果您正在使用可观察流AsyncPipe这样你就不用担心取消订阅了。异步管道将为您处理订阅和取消订阅。

什么时候?

好的,我们讲过了为什么——但是,我们取消订阅吗?在大多数情况下,取消订阅的最佳时间是当你的组件被销毁。Angularintroduced的ngOnDestroy ()生命周期方法:

ngOnDestroy ():在Angular销毁指令/组件之前进行清理。取消订阅可观察对象并分离事件处理程序,以避免内存泄漏。

如何?

有三种常见的方法:

  1. 存储订阅并调用退订()当组件被销毁时。
  2. 使用takeWhile ()操作符。
  3. 使用takeUntil ()操作符。

退订()

作为示例,让我们创建一个简单的可观测的流:

计数器=可观测的<数量>(观察者= >{控制台日志(“订阅”);指数=-1;常量时间间隔=setInterval(()= >{指数++;控制台日志(下一个:$ {指数});观察者下一个(指数);},1000);/ /拆卸返回()= >{控制台日志(“拆卸”);clearInterval(时间间隔);}

首先,导入OnDestroy@angular /核心以及ISubscription从rxjs接口:

进口{OnDestroy}“@angular /核心”;进口{ISubscription}“rxjs /订阅”;

接下来,我们实现抽象类并声明一个变量来存储对订阅的引用:

出口MyComponent实现了OnDestroy{私人订阅:ISubscription;}

然后我们订阅计数器可观察的,并存储对返回的引用订阅实例的订阅属性:

订阅=计数器订阅((价值)= >=价值,(错误)= >控制台错误(错误),()= >控制台日志(“完成”));

下一个,我们只需设置属性中已更新的价值。如果出现错误,则输出错误到控制台中,当发出完整通知并且从可观察对象取消订阅时,我们会记录字符串'complete'。

当组件被销毁时,我们调用退订()方法订阅:

ngOnDestroy(){订阅退订();}

如果订阅多个订阅,则不需要使用集合来存储所有订阅实例。相反,订阅可以有孩子订阅。简单地调用add ()方法添加其他子订阅。这是很有帮助的,因为所有的儿童订阅将被取消退订()父订阅。

让我们添加一个额外的订阅:

常量订阅=计数器订阅(价值= >控制台日志(价值));订阅添加(订阅);

我们只是add ()我们现有的新订阅订阅对象。然后,调用退订()方法,就像我们之前做的:

ngOnDestroy(){订阅退订();}

现在,所有子订阅以及它们的子订阅(如果存在的话)都是未订阅的。

takeWhile ()

取消订阅的另一种方法是使用http://reactivex.io/documentation/operators/takewhile.html接线员:

TakeWhile镜像源可观察对象,直到您指定的某些条件变为假,此时TakeWhile停止镜像源可观察对象并终止其自己的可观察对象。

首先,需要导入takeWhile ()接线员:

进口“rxjs /添加/运营商/ takeWhile”;

然后,让我们使用takeWhile ()操作员在管():

出口CounterTakeWhileComponent实现了OnInit,OnDestroy{:数量;计数器:可观测的<数量>;私人活着=真正的;ngOnInit(){控制台日志(“[takeWhile] ngOnInit”);计数器=可观测的<数量>(观察者= >{控制台日志(“[takeWhile]订阅”);指数=-1;常量时间间隔=setInterval(()= >{指数++;控制台日志([takeWhile]下:$ {指数});观察者下一个(指数);},1000);/ /拆卸返回()= >{控制台日志(“[takeWhile]拆卸”);clearInterval(时间间隔);}});计数器(takeWhile(()= >活着))订阅((价值)= >=价值,(错误)= >控制台错误(错误),()= >控制台日志(“[takeWhile]完成”));}ngOnDestroy(){控制台日志(“[takeWhile] ngOnDestory”);活着=;}}

CounterTakeWhile组件,我们使用活着属性来指示组件是否为活动的,然后将其切换为在组件的ngOnDestroy ()方法。

的问题takeWhile ()

重要的是要理解takeWhile ()当发出下一个通知时,操作符将只停止接收通知,从而从可观察源取消订阅。为了更好地解释这一点,让我们假设:

  1. 首先,我们订阅计数器可观察到的。
  2. 第二,价值0就会发出。
  3. 然后,价值1就会发出。
  4. 部件被破坏了ngOnDestroy ()方法被调用,并进行设置活着
  5. 然后,价值1就会发出。
  6. takeWhile ()操作符被调用,谓词返回false,因此可观察对象已经完成,并且我们取消了对任何其他通知的订阅。

注意,在上面的序列中,源可观察对象只在值之后才完成1就会发出。我们做了toggle活着,直到下一个通知我们takeWhile执行谓词函数。

可以成为应用程序中的问题。

为什么?因为如果在切换后没有发出另一个值活着布尔,那么我们将永远无法完成源可观察流——然后我们的应用程序就会出现内存泄漏。

有更好的方法吗?是的,使用takeUntil ()操作符。

takeUntil ()

takeUntil ()算子是完备可观测性的较好方法。

TakeUntil订阅并开始镜像可观察源。它还监视您提供的第二个观察对象。如果第二个可观察对象发出一个项或发送一个终止通知,则由TakeUntil返回的可观察对象将停止镜像源可观察对象并终止。

让我们来看看这是怎么回事:

出口CounterTakeUntilComponent实现了OnInit,OnDestroy{:数量;计数器:可观测的<数量>;私人退订:主题<无效>=主题();ngOnInit(){控制台日志(“[takeUntil] ngOnInit”);计数器=可观测的<数量>(观察者= >{控制台日志(“[takeUntil]订阅”);指数=-1;常量时间间隔=setInterval(()= >{指数++;控制台日志([takeUntil]下:$ {指数});观察者下一个(指数);},1000);/ /拆卸返回()= >{控制台日志(“[takeUntil]拆卸”);clearInterval(时间间隔);}});计数器(takeUntil(退订))订阅((价值)= >=价值,(错误)= >控制台错误(错误),()= >控制台日志(“[takeUntil]完成”));}ngOnDestroy(){控制台日志(“ngOnDestory”);退订下一个();退订完整的();}}

如您所见,此方法与使用takeWhile ()操作符。

有几点需要注意:

  • 首先,导入takeUntil ()操作符以及主题类。
  • 接下来,我们定义一个私有实例属性,名为退订,也就是主题。我们还创建一个新的实例主题,将泛型类型定义为无效
  • 我们使用takeUntil ()运营商管()方法之前调用订阅(),提供了退订可观察到的。
  • ngOnDestroy ()生命周期方法我们发出next ()通知,然后完成()退订可观察到的。订阅现已完成,而我们已立即取消订阅时ngOnDestroy ()方法在组件的生命周期中被调用。

takeWhile ()vstakeUntil ()

请查看示例并比较在使用时何时发出完整通知takeWhile ()vs。takeUntil ():

哪一种方法?

此时,你可能会问自己一个问题:

我应该用什么方法取消订阅?

首先,我建议您使用异步管道。让Angular框架为你管理订阅。

如果使用异步管道不是您需要的好解决方案,那么我建议使用takeUntil ()操作符。

布莱恩F爱

嗨,我是布莱恩。我对TypeScript, Angular和Node.js感兴趣。我和我最好的朋友邦妮结婚了,我住在波特兰,我经常滑雪。