首頁  >  文章  >  web前端  >  詳解Angular 中何時取消訂閱

詳解Angular 中何時取消訂閱

小云云
小云云原創
2017-12-12 11:05:291530瀏覽

你可能知道當你訂閱 Observable 物件或設定事件監聽時,在某個時間點,你需要執行取消訂閱操作,進而釋放作業系統的記憶體。否則,你的應用程式可能會出現記憶體洩漏。

接下來讓我們看一下,需要在 ngOnDestroy 生命週期鉤子中,手動執行取消訂閱操作的一些常見場景。本文主要介紹了淺談Angular 中何時取消訂閱,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

手動釋放資源場景

表單


#
export class TestComponent {

 ngOnInit() {
  this.form = new FormGroup({...});
  // 监听表单值的变化
  this.valueChanges = this.form.valueChanges.subscribe(console.log);
  // 监听表单状态的变化              
  this.statusChanges = this.form.statusChanges.subscribe(console.log);
 }

 ngOnDestroy() {
  this.valueChanges.unsubscribe();
  this.statusChanges.unsubscribe();
 }
}



##

export class TestComponent {
 constructor(private route: ActivatedRoute, private router: Router) { }

 ngOnInit() {
  this.route.params.subscribe(console.log);
  this.route.queryParams.subscribe(console.log);
  this.route.fragment.subscribe(console.log);
  this.route.data.subscribe(console.log);
  this.route.url.subscribe(console.log);
  
  this.router.events.subscribe(console.log);
 }

 ngOnDestroy() {
  // 手动执行取消订阅的操作
 }
}


以上方案也適用於其它的表單控制項。


路由


export class TestComponent {
 constructor(
  private renderer: Renderer2, 
  private element : ElementRef) { }

 ngOnInit() {
  this.click = this.renderer
    .listen(this.element.nativeElement, "click", handler);
 }

 ngOnDestroy() {
  this.click.unsubscribe();
 }
}


#Renderer 服務








#
export class TestComponent {
 constructor(private element : ElementRef) { }

 interval: Subscription;
 click: Subscription;

 ngOnInit() {
  this.interval = Observable.interval(1000).subscribe(console.log);
  this.click = Observable.fromEvent(this.element.nativeElement, 'click')
              .subscribe(console.log);
 }

 ngOnDestroy() {
  this.interval.unsubscribe();
  this.click.unsubscribe();
 }
}


Infinite Observables


#當你使用interval() 或fromEvent() 運算元時,你建立的是一個無限的Observable 物件。這樣的話,當我們不再需要使用它們的時候,就需要取消訂閱,手動釋放資源。


export class TestComponent {

 constructor(private store: Store) { }

 todos: Subscription;

 ngOnInit() {
   /**
   * select(key : string) {
   *  return this.map(state => state[key]).distinctUntilChanged();
   * }
   */
   this.todos = this.store.select('todos').subscribe(console.log); 
 }

 ngOnDestroy() {
  this.todos.unsubscribe();
 }
}

Redux Store



@Component({
 selector: 'test',
 template: `<todos [todos]="todos$ | async"></todos>`
})
export class TestComponent {
 constructor(private store: Store) { }
 
 ngOnInit() {
   this.todos$ = this.store.select(&#39;todos&#39;);
 }
}


無手動釋放資源場景


AsyncPipe


@Pipe({name: &#39;async&#39;, pure: false})
export class AsyncPipe implements OnDestroy, PipeTransform {
 // ...
 constructor(private _ref: ChangeDetectorRef) {}

 ngOnDestroy(): void {
  if (this._subscription) {
   this._dispose();
  }
 }
}

當元件銷毀時,async 管道會自動執行取消訂閱操作,進而避免記憶體外洩的風險。
Angular AsyncPipe 原始碼片段

export class TestDirective {
 @HostListener(&#39;click&#39;)
 onClick() {
  ....
 }
}


@HostListener






#

// subscribe
this.handler = this.renderer.listen(&#39;document&#39;, "click", event =>{...});

// unsubscribe
this.handler();


需要注意的是,如果使用@HostListener 裝飾器,新增事件監聽時,我們無法手動取消訂閱。如果需要手動移除事件監聽的話,可以使用以下的方式:


export class TestComponent {
 constructor(private http: Http) { }

 ngOnInit() {
  // 表示1s后发出值,然后就结束了
  Observable.timer(1000).subscribe(console.log);
  this.http.get(&#39;http://api.com&#39;).subscribe(console.log);
 }
}


##Finite Observable


當你使用HTTP 服務或timer Observable 物件時,你也不需要手動執行取消訂閱操作。

// 每隔1秒发出自增的数字,3秒后开始发送
var numbers = Rx.Observable.timer(3000, 1000);
numbers.subscribe(x => console.log(x));

// 5秒后发出一个数字
var numbers = Rx.Observable.timer(5000);
numbers.subscribe(x => console.log(x));


timer 運算子

運算子簽章


##複製程式碼

程式碼如下:


public static timer(initialDelay: number | Date, period: number, scheduler: Scheduler): Observable



運算元作用

timer 回傳一個發出無限自增數列的Observable,有一定的時間間隔,這個間隔由你來選擇。

運算子範例



export class TestComponent {
 constructor(private store: Store) { }

 private componetDestroyed: Subject = new Subject();
 todos: Subscription;
 posts: Subscription;

 ngOnInit() {
   this.todos = this.store.select(&#39;todos&#39;)
           .takeUntil(this.componetDestroyed).subscribe(console.log); 
           
   this.posts = this.store.select(&#39;posts&#39;)
           .takeUntil(this.componetDestroyed).subscribe(console.log); 
 }

 ngOnDestroy() {
  this.componetDestroyed.next();
  this.componetDestroyed.unsubscribe();
 }
}


#最終建議

你應該盡可能少的呼叫unsubscribe() 方法,你可以在RxJS: Don't Unsubscribe 這篇文章中了解與Subject 相關更多資訊。

具體範例如下:

public takeUntil(notifier: Observable): Observable<T>

####takeUntil 運算子######運算子簽章### ############
var interval = Rx.Observable.interval(1000);
var clicks = Rx.Observable.fromEvent(document, &#39;click&#39;);
var result = interval.takeUntil(clicks);

result.subscribe(x => console.log(x));
############運算子作用#########發出來源Observable 發出的值,直到notifier Observable 發出值。 ######運算子範例###############rrreee############相關推薦:########## ##詳解AngularJS中的表單驗證############詳解AngularJS中自訂指令的使用_AngularJS############詳解AngularJS中自訂篩選器_ AngularJS#######

以上是詳解Angular 中何時取消訂閱的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn