Angular 4에서 RxJS 구독 메모리 누수 해결

문제 상황

대시보드 페이지에서 라우팅으로 다른 페이지를 이동했다가 돌아오면 HTTP 요청이 중복으로 발생했다. 개발자 도구로 확인해보니 같은 API가 2번, 3번씩 호출되고 있었다.

원인은 간단했다. ngOnDestroy에서 Observable 구독을 해제하지 않아서였다.

export class DashboardComponent implements OnInit {
  ngOnInit() {
    this.dataService.getData()
      .subscribe(data => {
        this.items = data;
      });
  }
}

해결 방법

처음엔 Subscription 객체를 저장했다가 ngOnDestroy에서 unsubscribe()를 호출하는 방식을 썼다.

private subscription: Subscription;

ngOnInit() {
  this.subscription = this.dataService.getData()
    .subscribe(data => this.items = data);
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}

하지만 구독이 여러 개면 코드가 지저분해졌다. RxJS의 takeUntil 패턴이 더 깔끔했다.

private destroy$ = new Subject<void>();

ngOnInit() {
  this.dataService.getData()
    .pipe(takeUntil(this.destroy$))
    .subscribe(data => this.items = data);

  this.otherService.getOther()
    .pipe(takeUntil(this.destroy$))
    .subscribe(other => this.other = other);
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

결과

메모리 누수가 사라지고 페이지 이동 시 불필요한 HTTP 요청도 없어졌다. 앞으로 컴포넌트에서 구독할 때는 기본적으로 이 패턴을 적용하기로 했다.