ionic4-subscribe manage(订阅管理)

node 10.15.0
ionic 4.12.0
cordova 9.0
# platforms
cordova-android:8.0.0
cordova-ios: 5.0.0

为什么要管理订阅?

问题一:Memory leak

场景:
页面操作顺序:TestPage -> Test2Page ->(返回到) TestPage
Test2Page中模拟接口请求,发射数据并订阅
Chrome Memory 实验结果如下:

in TestPage

image.png

in Test2Page

image.png

back TestPage

image.png

此时Test2Page仍在内存中。

解决:在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 {
    return of([{id: 1, name: 'BBB'}]);
  }
  ngOnDestroy(): void {
    this.subs.unsubscribe();
  }
}

验证效果


image.png

问题二:Html render

场景和问题一一样,只是此时Test2Page页面数据源慢尚未返回,操作返回到TestPage,
回到TestPage后,接口数据到了,由于未取消订阅,所以会继续执行处理数据方法,然后渲染页面,但此时Test2Page页面已被销毁,无法渲染。


image.png

实现订阅管理

定义SubSink类

_subs: SubscriptionLike[] 存储订阅对象,便于取消订阅

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实现OnDestroy方法,及组件销毁时取消订阅

export class BaseComponent implements OnDestroy {
  subs = new SubSink();

  /**
   * Component销毁时会取消订阅
   */
  ngOnDestroy(): void {
    this.subs.unsubscribe();
  }
}

使用

首先继承BaseComponent;
其次构造方法:super();
最后将订阅对象赋值给 this.subs.sink,此时会调用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 {
    return of([{id: 1, name: 'BBB'}]);
  }

}

测试

image.png

参考文献

how-to-automatically-unsubscribe

总结

总的来说,取消订阅还是很有必要的;通过上面的方式,极大程度的方便了使用。

下一篇将介绍全局异常处理。

你可能感兴趣的:(ionic4-subscribe manage(订阅管理))