node 10.15.0
ionic 4.12.0
cordova 9.0
# platforms
cordova-android:8.0.0
cordova-ios: 5.0.0
為什么要管理訂閱?
問(wèn)題一:Memory leak
場(chǎng)景:
頁(yè)面操作順序:TestPage -> Test2Page ->(返回到) TestPage
Test2Page中模擬接口請(qǐng)求,發(fā)射數(shù)據(jù)并訂閱
Chrome Memory 實(shí)驗(yàn)結(jié)果如下:
in TestPage

image.png
in Test2Page

image.png
back TestPage

image.png
此時(shí)Test2Page仍在內(nèi)存中。
解決:在OnDestory()取消訂閱
export class Test2Page implements OnInit, OnDestroy {
subs: Subscription;
msgData = 'xxxxx2';
constructor() {
}
ngOnInit() {
this.subs = this.makeData()
.pipe(delay(5000))
.subscribe(
data => {
console.log('makeData2 -> data = ' + data[0].name);
this.msgData = data[0].name;
},
error2 => console.log('makeData2 -> error = ' + error2)
);
}
makeData(): Observable<any> {
return of([{id: 1, name: 'BBB'}]);
}
ngOnDestroy(): void {
this.subs.unsubscribe();
}
}
驗(yàn)證效果

image.png
問(wèn)題二:Html render
場(chǎng)景和問(wèn)題一一樣,只是此時(shí)Test2Page頁(yè)面數(shù)據(jù)源慢尚未返回,操作返回到TestPage,
回到TestPage后,接口數(shù)據(jù)到了,由于未取消訂閱,所以會(huì)繼續(xù)執(zhí)行處理數(shù)據(jù)方法,然后渲染頁(yè)面,但此時(shí)Test2Page頁(yè)面已被銷毀,無(wú)法渲染。

image.png
實(shí)現(xiàn)訂閱管理
定義SubSink類
_subs: SubscriptionLike[] 存儲(chǔ)訂閱對(duì)象,便于取消訂閱
const isFunction = (fn: any) => typeof fn === 'function';
export interface SubscriptionLike {
unsubscribe(): void;
}
export class SubSink {
protected _subs: SubscriptionLike[] = [];
constructor() {
}
add(...subscriptions: SubscriptionLike[]) {
this._subs = this._subs.concat(subscriptions);
}
set sink(subscription: SubscriptionLike) {
this._subs.push(subscription);
}
unsubscribe() {
this._subs.forEach(sub => sub && isFunction(sub.unsubscribe) && sub.unsubscribe());
this._subs = [];
}
}
定義BaseComponent類
BaseComponent實(shí)現(xiàn)OnDestroy方法,及組件銷毀時(shí)取消訂閱
export class BaseComponent implements OnDestroy {
subs = new SubSink();
/**
* Component銷毀時(shí)會(huì)取消訂閱
*/
ngOnDestroy(): void {
this.subs.unsubscribe();
}
}
使用
首先繼承BaseComponent;
其次構(gòu)造方法:super();
最后將訂閱對(duì)象賦值給 this.subs.sink,此時(shí)會(huì)調(diào)用SubSink類中的
this._subs.push(subscription);
export class Test2Page extends BaseComponent implements OnInit {
msgData = 'xxxxx2';
constructor(private changeRef: ChangeDetectorRef) {
super();
}
ngOnInit() {
this.subs.sink = this.makeData()
.pipe(delay(5000))
.subscribe(
data => {
console.log('makeData2 -> data = ' + data[0].name);
this.msgData = data[0].name;
this.changeRef.detectChanges();
},
error2 => console.log('makeData2 -> error = ' + error2)
);
}
makeData(): Observable<any> {
return of([{id: 1, name: 'BBB'}]);
}
}
測(cè)試

image.png
參考文獻(xiàn)
how-to-automatically-unsubscribe
總結(jié)
總的來(lái)說(shuō),取消訂閱還是很有必要的;通過(guò)上面的方式,極大程度的方便了使用。
下一篇將介紹全局異常處理。