官方的编辑#3答案(和变体)效果很好,但让我困扰的是可观察订阅周围的业务逻辑“混乱”。以下是另一种使用包装器的方法。引用:“警告:实验性代码”。文件subscribeAndGuard.ts用于创建一个新的Observable扩展来包装.subscribe(),并在其中包装ngOnDestroy()。使用方式与.subscribe()相同,除了额外的第一个参数引用组件。
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
const subscribeAndGuard = function(component, fnData, fnError = null, fnComplete = null) {
const sub: Subscription = this.subscribe(fnData, fnError, fnComplete);
if (!component.ngOnDestroy) {
throw new Error('To use subscribeAndGuard, the component must implement ngOnDestroy');
}
const saved_OnDestroy = component.ngOnDestroy;
component.ngOnDestroy = () => {
console.log('subscribeAndGuard.onDestroy');
sub.unsubscribe();
component.ngOnDestroy = saved_OnDestroy;
component.ngOnDestroy();
};
return sub;
};
Observable.prototype.subscribeAndGuard = subscribeAndGuard;
declare module 'rxjs/Observable' {
interface Observable<T> {
subscribeAndGuard: typeof subscribeAndGuard;
}
}
这里有一个组件,它有两个订阅,一个带有包装器,一个不带。唯一的注意事项是它必须实现OnDestroy(如果需要,则为空),否则Angular不知道调用包装版本。
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import './subscribeAndGuard';
@Component({
selector: 'app-subscribing',
template: '<h3>Subscribing component is active</h3>',
})
export class SubscribingComponent implements OnInit, OnDestroy {
ngOnInit() {
Observable.interval(1000)
.subscribeAndGuard(this,
(data) => { console.log('Guarded:', data); },
(error) => { },
() => { }
);
Observable.interval(1000)
.subscribe(
(data) => { console.log('Unguarded:', data); },
(error) => { },
() => { }
);
}
ngOnDestroy() {
console.log('SubscribingComponent.OnDestroy');
}
}
这里提供一个演示用的plunker:链接
另外注意:
在“官方”解决方案中,可以通过在订阅之前使用takeWhile()代替takeUntil(),以及使用简单的布尔变量而不是另一个Observable来简化代码并在ngOnDestroy()中处理。
@Component({...})
export class SubscribingComponent implements OnInit, OnDestroy {
iAmAlive = true;
ngOnInit() {
Observable.interval(1000)
.takeWhile(() => { return this.iAmAlive; })
.subscribe((data) => { console.log(data); });
}
ngOnDestroy() {
this.iAmAlive = false;
}
}
http-requests
的Subscription
可以被忽略,因为它们只调用一次onNext
,然后调用onComplete
。相反,Router
会重复地调用onNext
,并且可能永远不会调用onComplete
(不确定......)。对于从Event
获得的Observable
也是如此。所以我猜应该将它们取消订阅。 - Robert Psubscribe
的调用本身。 - seangwrighttypescript
中,将明确取消订阅作为一种“肌肉记忆”。即使是http
订阅也要这样做。例如:如果你的Http.get()
在响应上完成。如果你的服务器 API 花费了10 秒
来响应,并且你的组件在调用后的5 秒
内被销毁,那么你的响应将在组件销毁之后的5 秒
到达。这将触发一个上下文不正确的执行,这比 Angular 文档中指出的内存泄漏部分更糟糕。 - Avid Coder