浅谈Angular 中何时取消订阅

网友投稿 492 2023-03-15


浅谈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: ``

})

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

}

}

}

@HostListener

export class TestDirective {

@HostListener('click')

onClick() {

....

}

}http://

需要注意的是,如果使用 @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);

}

}

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:ZfZCuYU Subscription;

posts: Subscription;

ngOnInit() {

this.todos = this.store.select('todos')

ZfZCuYU.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

操作符作用

发出源 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));


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:开放接口管理平台(开放接口英文)
下一篇:详解从零搭建 vue2 vue
相关文章

 发表评论

暂时没有评论,来抢沙发吧~