Home  >  Article  >  Web Front-end  >  Detailed explanation of when to cancel subscription in Angular

Detailed explanation of when to cancel subscription in Angular

小云云
小云云Original
2017-12-12 11:05:291579browse

You may know that when you subscribe to an Observable object or set up an event listener, at some point in time, you need to perform an unsubscription operation to release the operating system's memory. Otherwise, your application may suffer from memory leaks.

Next, let’s take a look at some common scenarios that require manual unsubscription operations in the ngOnDestroy life cycle hook. This article mainly introduces a brief discussion on when to cancel a subscription in Angular. The editor thinks it is quite good. Now I will share it with you and give you a reference. Let’s follow the editor to take a look, I hope it can help everyone.

Manual release resource scenario

Form


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();
 }
}


The above solution is also applicable to other form controls.

Routing


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() {
  // 手动执行取消订阅的操作
 }
}


Renderer Service


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();
 }
}


Infinite Observables

When you use the interval() or fromEvent() operator, you create an infinite Observable object. In this case, when we no longer need to use them, we need to unsubscribe and release the resources manually.


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();
 }
}


Redux Store


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();
 }
}


No need to manually release resource scenarios

AsyncPipe


@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;);
 }
}


When the component is destroyed, the async pipeline will automatically perform the unsubscription operation to avoid the risk of memory leaks.

Angular AsyncPipe source code snippet


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

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


##@HostListener



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


It should be noted that if you use the @HostListener decorator and add event listening, we cannot manually unsubscribe. If you need to manually remove event monitoring, you can use the following method:


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

// unsubscribe
this.handler();


Finite Observable

When you use HTTP services or timer Observable objects, you do not need to manually perform unsubscription operations.


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);
 }
}


timer operator

Operator signature



Copy code The code is as follows:

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


Operator function


#timer returns an Observable that emits an infinite auto-increasing sequence, with a certain time interval. This interval is chosen by you.

Operator examples


##

// 每隔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));


Final advice


You should Call the unsubscribe() method as little as possible. You can learn more about Subject in the article RxJS: Don't Unsubscribe.

Specific examples are as follows:

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();
 }
}

##takeUntil operator

Operator signature


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


Operator function

Emits the value emitted by the source Observable until the notifier Observable emits a value.

Operator examples


##

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));


##Related recommendations:


Detailed explanation of form validation in AngularJS


Detailed explanation of the use of custom instructions in AngularJS_AngularJS

Detailed explanation of custom filters in AngularJS_ AngularJS

The above is the detailed content of Detailed explanation of when to cancel subscription in Angular. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn