簡介
Angular 處理取消訂閱可觀察對象的操作,比如從 HTTP 服務返回的可觀察對象或者使用 async 管道時。然而,對于其他情況,管理所有訂閱并確保取消長期存在的訂閱可能會變得困難。而且,取消大部分訂閱的策略也會帶來自己的問題。
在本文中,您將看到一個依賴于手動訂閱和取消訂閱的 Angular 應用示例。然后,您將比較它與使用 takeUntil
操作符來聲明性地管理訂閱的 Angular 應用示例。
先決條件
如果您想跟著本文學習,您需要:
- 對 RxJS 庫有一定的了解,特別是
Observable
和Subscription
將會有所幫助。 - 對 Apollo 和 GraphQL 有一定的了解會有所幫助,但不是必需的。
本教程經過 Node v15.3.0、npm
v6.14.9、@angular/core
v11.0.4、rxjs
v6.6.3、apollo-angular
v2.1.0、graph-tag
v2.11.0 的驗證。本文已經根據從早期版本的 @angular/core
和 rxjs
遷移的變化進行了編輯。
手動取消訂閱
讓我們從一個示例開始,您將在其中手動取消訂閱兩個訂閱。
在這個示例中,代碼正在訂閱 Apollo 的 watchQuery
來從 GraphQL 端點獲取數據。
該代碼還創建了一個間隔可觀察對象,當調用 onStartInterval
方法時,您將訂閱該對象。
import { Component, OnInit, OnDestroy } from '@angular/core';import { Subscription, interval } from 'rxjs';import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {myQuerySubscription: Subscription;myIntervalSubscription: Subscription;constructor(private apollo: Apollo) {}ngOnInit() {this.myQuerySubscription = this.apollo.watchQuery<any>({query: gql`query getAllPosts {allPosts {titledescriptionpublishedAt}}`}).valueChanges.subscribe(({data}) => {console.log(data);});}onStartInterval() {this.myIntervalSubscription = interval(250).subscribe(value => {console.log('Current value:', value);});}ngOnDestroy() {this.myQuerySubscription.unsubscribe();if (this.myIntervalSubscription) {this.myIntervalSubscription.unsubscribe();}}
}
現在想象一下,您的組件有許多類似的訂閱,當組件被銷毀時,確保一切都被取消訂閱可能會變得相當復雜。
使用 takeUntil
聲明性地取消訂閱
解決方案是使用 takeUntil
操作符來組合訂閱,并使用一個在 ngOnDestroy
生命周期鉤子中發出真值的主題。
以下代碼片段執行了完全相同的操作,但這次代碼將以聲明性的方式取消訂閱。您會注意到一個額外的好處是,您不再需要保留對我們訂閱的引用。
import { Component, OnInit, OnDestroy } from '@angular/core';import { Subject, interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {destroy$: Subject<boolean> = new Subject<boolean>();constructor(private apollo: Apollo) {}ngOnInit() {this.apollo.watchQuery<any>({query: gql`query getAllPosts {allPosts {titledescriptionpublishedAt}}`}).valueChanges.pipe(takeUntil(this.destroy$)).subscribe(({data}) => {console.log(data);});}onStartInterval() {interval(250).pipe(takeUntil(this.destroy$)).subscribe(value => {console.log('Current value:', value);});}ngOnDestroy() {this.destroy$.next(true);this.destroy$.unsubscribe();}
}
請注意,使用 takeUntil
這樣的操作符而不是手動取消訂閱也將完成可觀察對象,觸發可觀察對象上的任何完成事件。
請確保檢查您的代碼,以確保這不會產生任何意外的副作用。
結論
在本文中,您學習了如何使用 takeUntil
聲明性地取消訂閱。取消不必要的訂閱有助于防止內存泄漏。聲明性地取消訂閱使您不需要對訂閱保留引用。
還有其他類似的 RxJS 操作符 - 如 take
、takeWhile
和 first
- 它們都會完成可觀察對象。
如果您想了解更多關于 Angular 的知識,請查看我們的 Angular 主題頁面,了解練習和編程項目。