안녕하세요. 꼬동입니다.
오늘은 RxJS 구독해제 패턴 심화편을 알아보려합니다.
사실 제 주제에 "심화편"이라고 글 쓰는 것도 웃기지만, 폼 좀 잡아보고자 심화편이라고 썼습니다.
글을 시작하기 전에 "심화편" 전에 다룰 수 있는 구독해제 내용은 async / unsubscribe 메소드 / take / takeWhile / takeUntil 등이 있을텐데요.
뭐 이런 구독해제 패턴이야 RxJS 홈페이지 들어가면 더 자세히 알려주니, 사용 방법은 홈페이지를 참고하시면 될거 같고, 저는 좀 더 딥하게 알아보려고 합니답.
오늘 다룰 주제는 takeWhile vs takeUntil과 ngneat/until-destroy입니다.
takeWhile vs takeUntil
구독해제를 위한 오퍼레이터 두 개를 둘고 왔습니다.
takeWhile의 경우엔, 전달 받은 함수의 리턴값이 false가 되는 순간 구독을 해지합니다.
takeUntil의 경우엔, 전달받은 observable이 방출할 경우 구독을 해지합니다.
언뜻 봐선 비슷해보입니다.
그런데 은근 둘이 다른 점이 존재합니다.
그 다른 점을 명확하게 나타낼 수 있는 예제 코드를 보여드리도록 하겠습니다.
takeWhile
import { fromEvent, interval } from 'rxjs';
import { take, takeWhile, tap } from 'rxjs/operators';
console.clear();
let flag = true;
interval(1000)
.pipe(
tap(console.log),
takeWhile(() => flag)
)
.subscribe();
fromEvent(document, 'click')
.pipe(take(1))
.subscribe(() => (flag = false));
https://stackblitz.com/edit/rxjs-qpfyoj?devtoolsheight=60
보시면 클릭 후 한 번 더 데이터를 받아와서 출력을 합니다.
아래와 같이 말이죠.
1
2
3
// 클릭 !!!
4
// 종료
마치 이별 뒤, 미련이 남은 사람이 한 번 뒤돌아보고 종료되는 그런 아련함이 있습니다.
takeUntil
takeUntil은 어떨까요. 쿨하게 이별을 감내하는 친구일까요 ?
코드는 아래와 같습니다.
import { of } from 'rxjs';
import { fromEvent, interval } from 'rxjs';
import { map, takeUntil, tap } from 'rxjs/operators';
console.clear();
let flag = true;
interval(1000)
.pipe(
tap(console.log),
takeUntil(fromEvent(document, 'click'))
)
.subscribe();
https://stackblitz.com/edit/rxjs-r5khjm?devtoolsheight=60
이 친구는 takeWhile과 같은 친구와는 다르게 마음을 돌리면 미련 따윈 남기지 않는 그런 친구였습니다.
클릭 후 그 뒤엔 신경도 쓰진 않으니까요.
1
2
// 클릭 !!!
// 종료
즉, 둘 사이의 문제는 다음과 같습니다.
takeWhile의 경우엔 들어오는 알림에 의해 트리거가 되며, 그 후 구독을 취소합니다.
takeUntil은 통과한 Observable에 의해 트리거가 되고요.
정리하자면, takeWhile은 takeUntil보다 Observable flow를 한 번 더 허용해주는 친구였던거죠.
이게 큰 문제가 될 수 있습니다. 만약, takeWhile이 단순히 console에 숫자를 표현하는게 아닌 무거운 Http Call을 했다고 생각해봅시다.
뭐 기존에 사용할 땐 상관없는데, 얘를 구독해지 하기 위해선 Http Call을 한 번 더 호출해야한다는 점이 큰 문제가 됩니다.
그렇기 때문에 이렇게 질문을 할 수 있습니다.
애ㅔ베베에베ㅔ베베베ㅔ베ㅔㅔ베 takeWhile을 pipeline 제일 처음에 두면 되잖아 헤에에에ㅔㅇ베베베ㅔ베에베베
넹 맞습니당.
그렇게하면 불필요한 리소스를 줄일 수 있져.
하지만 이렇게 하면, inner Observable을 통해서 이를 구독해제 할 수 없다는 점을 알고 계셔야겠져 ?
takeWhile과 takeUntil 모두 홀륭한 operators이기 때문에 배척하지 마세요.
코드는 문제가 없습니다. 문제가 있는건 항상 저희였죠..
그렇기 때문에 조심하고 사용한다면, 충분히 좋은 operators가 될 수 있겠습니다.
앞서 말했듯이 구독해제를 하는 방법은 수없이 많습니다.
특히 Component가 destroy되는 순간에 구독해제를 해줘야 메모리 누수를 막을 수 있죠. 그렇기에 한 친구씩 찾아서 구독 해제를 시켜줘야합니다.
그렇다고 진짜 한 친구 씩 찾아서 unsubscribe 메소드를 호출하고 해야할까요 ?
인간이란 편리함을 찾기 위해 사는 동물
귀찮음이 많은 사람이 개발을 잘합니다.
그 귀찮음이 많고 정말 멋지시고 !! 똑똑하시고 !! 존경스럽구 !! 든든하신 분이 모듈을 하나 추천을 해줬는데요. 그 모듈에 대해 알아보도록 합시다.
@ngneat/until-destroy
https://github.com/ngneat/until-destroy
해당 모듈 역시 destroy될 떄 구독해제를 해주는 친절한 모듈입니다.
그 전에 참고해야하는 점을 몇 가지 살펴봅시다.
- @ngneat/until-destroy@8+의 경우엔 Angular 10.0.5 version 이상이 되어야합니다. 그 이하 버전은 @ngneat/until-destroy@7을 쓰세용
- npm install @ngneat/until-destroy / yarn add @ngneat/until-destroy로 설치가 가능합니다.
설치했다면 바로 사용해봐야죠.
이 분들이 제공하는 기본 코드는 위와 같습니다.
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
@UntilDestroy()
@Component({})
export class InboxComponent {
ngOnInit() {
interval(1000)
.pipe(untilDestroyed(this))
.subscribe();
}
}
오메 저도 이거 코드로 된건 적으면서 처음 봤는데 겁나 간단하네영 ;; 직관적이기도 하고
게다가 무슨 property를 사용하면, 자동으로 해제를 해준다고도 합니다.
@UntilDestroy({ checkProperties: true })
@Component({})
export class HomeComponent {
// We'll dispose it on destroy
subscription = fromEvent(document, 'mousemove').subscribe();
}
굳이 pipe로다가 호들갑 안 떨고 젠틀하게 구독해제를 할 수 있네요.
@UntilDestroy({ arrayName: 'subscriptions' })
@Component({})
export class HomeComponent {
subscriptions = [
fromEvent(document, 'click').subscribe(),
fromEvent(document, 'mousemove').subscribe()
];
ngOnInit() {
interval(1000).pipe(untilDestroyed(this));
}
}
위의 코드는 destroy가 되면 subscriptions이라는 이름을 가진 배열에 담긴 subscription을 구독해제를 해준다고 합니다.
destroy 시 구독을 끊기 싫으면 아래와 같이도 사용할 수 있네요.
@UntilDestroy({ checkProperties: true, blackList: ['subscription1'] })
@Component({})
export class HomeComponent {
subscription1: Subscription;
subscription2: Subscription;
constructor() {
this.subscription1 = new Subject().subscribe();
this.subscription2 = new Subject().subscribe();
}
}
해당 모듈을 사용하면, 좀 더 깔끔하고 정확하게 구독해제를 할 수 있겠죠?
어서 영업하세요 !!!
다양한 구독해제를 알아봤습니다.
사실 "심화편" 이라고 했는데, 글 다 적고 보니 그렇게 심화 아니네요
죄송합니당
이상 RxJS 구독해제 패턴 심화편였습니다. ^_^
'Web + APP > Angular' 카테고리의 다른 글
iOS 한글 buffer 문제 (1) | 2021.09.11 |
---|---|
Angular Flex-Layout using MediaObserver (2) | 2021.08.28 |
Async Pipe 뜯어먹기 (4) | 2021.05.30 |
RxJS가 해결하려고 했던 문제 3 (6) | 2021.05.20 |
RxJS가 해결하려고 했던 문제 2 (0) | 2021.05.19 |