Angular 中何时取消订阅

发布时间:2019-06-10 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Angular 中何时取消订阅脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

你可能知道当你订阅 Observable 对象或设置事件监听时,在某个时间点,你需要执行取消订阅操作,进而释放操作系统的内存。否则,你的应用程序可能会出现内存泄露

接下来让我们看一下,需要在 ngOnDestroy 生命周期钩子中,手动执行取消订阅操作的一些常见场景。

手动释放资场景

表单

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

Renderer 服务

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

当你使用 interval()FromEvent() 操作符时,你创建的是一个无限的 Observable 对象。这样的话,当我们不再需要使用它们的时候,就需要取消订阅,手动释放资源。

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

无需手动释放资源场景

AsyncPiPE

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

当组件销毁时,async 管道会自动执行取消订阅操作,进而避免内存泄露风险

Angular AsyncPipe 源码片段

@Pipe({name: 'async', pure: false})
export class AsyncPipe implements OnDestroy, PipeTransform {
  // ...
  constructor(private _ref: ChangedetectorRef) {}

  ngOnDestroy(): void {
    if (this._subscription) {
      this._dispose();
    }
  }
}
@H_512_310@@HostListener
export class TestDirective {
  @HostListener('click')
  onClick() {
    ....
  }
}

需要注意的是,如果使用 @HostListener 装饰器,添加事件监听时,我们无法手动取消订阅。如果需要手动移除事件监听的话,可以使用以下的方式:

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

// unsubscribe
this.handler();

Finite Observable

当你使用 HTTP 服务或 timer Observable 对象时,你也不需要手动执行取消订阅操作。

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

  ngOnInit() {
    // 表示1s后发出值,然后就结束了
    Observable.timer(1000).subscribe(console.log);
    this.http.get('http://api.COM').subscribe(console.log);
  }
}
@H_510_406@timer 操作符
  • 操作符签名

public static timer(initialDelay: number | Date, period: number, scheduler: Scheduler): Observable
  • 操作符作用

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

最终建议

应该尽可能少的调用 unsubscribe() 方法,你可以在 RxJS: Don’t Unsubscribe 这篇文章了解与 Subject 相关更多信息。

具体示例如下:

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

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

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

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

takeUntil 操作符

  • 操作符签名

public takeUntil(notifier: Observable): Observable<T>
  • 操作符作用

发出源 Observable 发出的值,直到 notifier Observable 发出值。

  • 操作符示例

var interval = Rx.Observable.interval(1000);
var clicks = Rx.Observable.fromEvent(document, 'click');
var result = interval.takeUntil(clicks);

result.subscribe(x => console.log(x));

参考资源

脚本宝典总结

以上是脚本宝典为你收集整理的Angular 中何时取消订阅全部内容,希望文章能够帮你解决Angular 中何时取消订阅所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。