官方编辑#3 答案(和变体)效果很好,但让我感到困惑的是围绕可观察订阅的业务逻辑的“混乱”。
这是使用包装器的另一种方法。
警告:实验代码
文件subscribeAndGuard.ts用于创建一个新的 Observable 扩展来 wrap.subscribe()
并在其中 wrap ngOnDestroy()
。
用法与 相同.subscribe()
,除了引用组件的附加第一个参数。
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
const subscribeAndGuard = function(component, fnData, fnError = null, fnComplete = null) {
// Define the subscription
const sub: Subscription = this.subscribe(fnData, fnError, fnComplete);
// Wrap component's onDestroy
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();
// Note: need to put original back in place
// otherwise 'this' is undefined in component.ngOnDestroy
component.ngOnDestroy = saved_OnDestroy;
component.ngOnDestroy();
};
return sub;
};
// Create an Observable extension
Observable.prototype.subscribeAndGuard = subscribeAndGuard;
// Ref: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
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() {
// This subscription will be terminated after onDestroy
Observable.interval(1000)
.subscribeAndGuard(this,
(data) => { console.log('Guarded:', data); },
(error) => { },
(/*completed*/) => { }
);
// This subscription will continue after onDestroy
Observable.interval(1000)
.subscribe(
(data) => { console.log('Unguarded:', data); },
(error) => { },
(/*completed*/) => { }
);
}
ngOnDestroy() {
console.log('SubscribingComponent.OnDestroy');
}
}
一个演示 plunker 在这里
附加说明:
重新编辑 3 - “官方”解决方案,这可以通过在订阅前使用 takeWhile() 而不是 takeUntil() 来简化,并在 ngOnDestroy 中使用一个简单的布尔值而不是另一个 Observable。
@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;
}
}