RXJS - takeUntil

Keeping too many subscription objects around is a sign you’re managing your subscriptions imperatively, and not taking advantage of the power of Rx.
在代碼中keep太多的subscription對象是不好的,意味著管理訂閱太過生硬,且沒有充分利用Rx。

For example,

class MyGenericComponent extends SomeFrameworkComponent {

updateData(data) {
  // do something framework-specific to update your component here.
}

onMount() {
  this.dataSub = this.getData().subscribe(data => this.updateData(data));
  const cancelBtn = this.element.querySelector(‘.cancel-button’);
  const rangeSelector = this.element.querySelector(‘.rangeSelector’);

  this.cancelSub = Observable.fromEvent(cancelBtn, ‘click’)
   .subscribe(() => {
    this.dataSub.unsubscribe();
   });

  this.rangeSub = Observable.fromEvent(rangeSelector, ‘change’)
   .map(e => e.target.value)
   .subscribe((value) => {
    if (+value > 500) {
      this.dataSub.unsubscribe();
    }
   });
}

onUnmount() {
  this.dataSub.unsubscribe();
  this.cancelSub.unsubscribe();
  this.rangeSub.unsubscribe();
}
}

The ugliness here is I’m imperatively managing unsubscriptions in multiple places in this fairly trivial example.
這代碼的糟糕之處在于,在這個相當瑣碎的示例中,在多個地方強制管理取消訂閱。

The only real advantage to using this approach would be performance. Since you’re using fewer abstractions to get the job done, it’s likely to perform a little better. This is unlikely to have a noticeable effect in the majority of web applications however, and I don’t think it’s worth worrying about.
這種方法的惟一的優(yōu)勢是性能。因為使越少的抽象來完成工作,執(zhí)行起來性能就會越好些。然而,這在大多數web應用程序中不太可能產生明顯的影響。

Alternatively, you can always combine subscriptions into a single subscription by creating a parent subscription and adding all of the others like children. But at the end of the day, you’re still doing the same thing, and you’re probably missing out.Compose your subscription management with takeUntil:
另一種方法就是創(chuàng)建父訂閱并添加所有其他訂閱(作為子訂閱),將訂閱合并為單個訂閱。使用takeUntil進行訂閱的管理:

class MyGenericComponent extends SomeFrameworkComponent {
updateData(data) {
  // do something framework-specific to update your component here.
}

onMount() {
   const data$ = this.getData();
   const cancelBtn = this.element.querySelector(‘.cancel-button’);
   const rangeSelector = this.element.querySelector(‘.rangeSelector’);
   const cancel$ = Observable.fromEvent(cancelBtn, 'click');
   const range$ = Observable.fromEvent(rangeSelector, 'change').map(e => e.target.value);
   const stop$ = Observable.merge(cancel$, range$.filter(x => x > 500))
   this.subscription = data$.takeUntil(stop$).subscribe(data => this.updateData(data));
}

onUnmount() {
  this.subscription.unsubscribe();
}
}

The first thing you might notice is it’s less code. That’s just one benefit. Another thing that’s happened here is I have composed a stream of stop$ events that kill the data stream. That means when I decide I want to add another condition to kill the data stream, like say a timer, I can simply merge a new observable into stop$. Another thing that is readily apparent is I only have one subscription object that I’m managing imperatively.
首先,代碼量變少了。代碼當中,create一個stop$事件流,通過takeUntil來終止數據流。如果后續(xù)想要再添加另一個條件來終止數據流時,比如一個計時器,就可以簡單地將一個新的observable對象合并到stop$中。除此以外,只強制管理一個subscription對象。

Another advantage to this approach is it actually completes the observable. That means there’s a completion event that can be handled anytime you want to kill your observable. If you just call unsubscribe on a returned subscription object, there’s no way you’ll be notified that the unsubscription happened. However if you use takeUntil (or others listed below), you will be notified the observable has stopped via your completion handler.
另一個優(yōu)點是, 這種方法實際上完成了observable。任何時候都可以用一個完成事件來殺死observable對象。如果只是在返回的subscription對象上unsubscribe,則無法知曉取消訂閱的發(fā)生。

The last advantage I’ll point out is the fact that you’re actually “wiring everything up” by calling subscribe in one place, this is advantageous because with discipline it becomes much, much easier to locate where you’re starting your subscriptions in your code. Remember, observables don’t do anything until you subscribe to them, so the point of subscription is an important piece of code.
最后一個優(yōu)點是,通過在一個地方調用subscribe是非常有利的。因為只有這樣,在代碼中查找訂閱的起始位置會變得非常容易。在訂閱之前,observables不會做任何事情。

There is one disadvantage here in terms of RxJS semantics, but it’s barely worth worrying about in the face of the other advantages. The semantic disadvantage is that completing an observable is a sign that the producer wants to tell the consumer it’s done, where unsubscribing is the consumer telling the producer it no longer cares about the data.
當然,這個方法在RxJS語義方面也有一個缺點,但是在其他優(yōu)點面前,它幾乎不值得擔心。語義上的缺點是,完成一個observable對象是指生產者想要告訴消費者它已經完成了,而取消訂閱是消費者告訴生產者它不再關心數據。

There will also be a very slight performance difference between this and just calling unsubscribe imperatively. However, it’s unlikely that the perf hit will be anything noticeable in the mass-majority of applications.
這與直接unsubscribe 在性能上也有細微的差別。

The general rule is that takeUntil should be the last operator in the sequence(otherwise, leak the subscription after it).
一個規(guī)則是 takeUntil應該是最后一個操作子。

Other Operators

  1. take(n): emits N values before stopping the observable.

  2. takeWhile(predicate): tests the emitted values against a predicate, if it returns false, it will complete.

  3. first(): emits the first value and completes.

  4. first(predicate): checks each value against a predicate function, if it returns true, the emits that value and completes.

Refer:
angular-rxjs-when-should-i-unsubscribe-from-subscription

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • By clicking to agree to this Schedule 2, which is hereby ...
    qaz0622閱讀 1,651評論 0 2
  • 說是寫作有點過了,僅僅是用英語記錄當天的所思所感所想,只有3、5句話。但記得有人說過:你想要去到哪里,就從哪里開始...
    搬布閱讀 967評論 0 5
  • 寒假坐車回家坐的動車,雖然對一個住在京郊的地方人來說最平常的是做大巴,但之前覺得動車即快又人少,這對一個對春運有著...
    零零麒閱讀 135評論 0 1
  • 北京的城市管理是非常好的,是特別干凈的一個城市,秩序優(yōu)良,綠化也非常好,最讓我滿意的是北京的交通,擁堵的現象幾乎沒...
    行者超閱讀 233評論 5 4

友情鏈接更多精彩內容