[ReactiveX]Subject의 개요 및 사용법
RxJS 이해하기
ReactiveX의 javascript 버전으로 반응형 프로그래밍을 용이하게 도와주는 라이브러리다.
Subject 이해하기
ReactiveX에서는 일반적으로 Observable로 대부분의 기능 구현이 가능하지만 Observable에서 구현할 수 없는 기능이 있는데 이를 보완해주는 것이 바로 Subject다.
Observable과 Subject의 차이점
용어 이해하기
Observable : 관찰할 수 있는 대상, 발행물, 유튜브
Observer : 관찰자, 구독자
발행 시점
Observable의 경우 Subscribe하는 시점에 발행되며, Subject의 경우 개발자가 원하는 시점에 발행할 수 있다.
발행 대상
Observable이 unicast인 것에 반해 Subject는 Multicaste로 보다 많은 Observers에게 값을 전달할 수 있다. 이를 각각 cold 발행, hot 발행이라고도 부른다.
구독 가능한 내용
Observable의 경우 각 구독자가 구독한 시점에 따로 발행하기 때문에 과거의 데이터도 구독할 수 있다. 이에 반해 Subject의 경우 모든 구독자에게 똑같이 발행하기 때문에 현재 발행 내용만을 구독할 수 있다. 비유하자면 Netflix와 TV채널과 같다.
구성 함수 종류
next(v)
: 발행
error(e)
: 에러 반환
complete()
: 발행 완료
subscribe()
: 구독
차이점 코드로 이해하기
Obsarvable
const { interval } = rxjs
const obs$ = interval(1000)
obs$.subscribe(x => console.log('바로구독: ' + x))
setTimeout(_ => {
obs$.subscribe(x => console.log('3초 후 구독: ' + x))
}, 3000)
setTimeout(_ => {
obs$.subscribe(x => console.log('5초 후 구독: ' + x))
}, 5000)
setTimeout(_ => {
obs$.subscribe(x => console.log('10초 후 구독: ' + x))
}, 10000)
<console>
“바로구독: 0”
“바로구독: 1”
“바로구독: 2”
“3초 후 구독: 0”
“바로구독: 3”
“3초 후 구독: 1”
“바로구독: 4”
“5초 후 구독: 0”
“3초 후 구독: 2”
“바로구독: 5”
“5초 후 구독: 1”
“3초 후 구독: 3”
“바로구독: 6”
“5초 후 구독: 2”
“3초 후 구독: 4”
“바로구독: 7”
“5초 후 구독: 3”
“3초 후 구독: 5”
“바로구독: 8”
“5초 후 구독: 4”
“3초 후 구독: 6”
“바로구독: 9”
“10초 후 구독: 0”
“5초 후 구독: 5”
“3초 후 구독: 7”
“바로구독: 10”
“10초 후 구독: 1”
“5초 후 구독: 6”
“3초 후 구독: 8”
“바로구독: 11”
“10초 후 구독: 2”
“5초 후 구독: 7”
“3초 후 구독: 9”
“바로구독: 12”
“10초 후 구독: 3”
“5초 후 구독: 8”
“3초 후 구독: 10”
“바로구독: 13”
Subject
const { Subject } = rxjs
const subject = new Subject()
setTimeout(_ => {
let x = 0
setInterval (_ => {
subject.next(x++)
}, 2000)
}, 5000)
subject.subscribe(x => console.log('바로구독: ' + x))
setTimeout(_ => {
subject.subscribe(x => console.log('3초 후 구독: ' + x))
}, 3000)
setTimeout(_ => {
subject.subscribe(x => console.log('10초 후 구독: ' + x))
}, 10000)
setTimeout(_ => {
subject.subscribe(x => console.log('14초 후 구독: ' + x))
}, 14000)
<console>
“바로구독: 0”
“3초 후 구독: 0”
“바로구독: 1”
“3초 후 구독: 1”
“바로구독: 2”
“3초 후 구독: 2”
“10초 후 구독: 2”
“바로구독: 3”
“3초 후 구독: 3”
“10초 후 구독: 3”
“바로구독: 4”
“3초 후 구독: 4”
“10초 후 구독: 4”
“14초 후 구독: 4”
“바로구독: 5”
“3초 후 구독: 5”
“10초 후 구독: 5”
“14초 후 구독: 5”
“바로구독: 6”
“3초 후 구독: 6”
“10초 후 구독: 6”
“14초 후 구독: 6”
“바로구독: 7”
“3초 후 구독: 7”
“10초 후 구독: 7”
Subject의 종류 및 비교
Subject
앞서 발행된 것은 구독할 수 없으며 발행된 시점의 것만 구독할 수 있다.
BehaviorSubject
앞서 발행된 마지막 데이터를 저장 후 다음 구독자에게 발행한다. 초기값을 설정할 수 있다는 특징이 있다
const { BehaviorSubject } = rxjs
const subject = new BehaviorSubject(0) // 초기값이 있음
subject.subscribe((x) => console.log('A: ' + x))
subject.next(1)
subject.next(2)
subject.next(3)
subject.subscribe((x) => console.log('B: ' + x))
subject.next(4)
subject.next(5)
<console>
“A: 0”
“A: 1”
“A: 2”
“A: 3”
“B: 3”
“A: 4”
“B: 4”
“A: 5”
“B: 5”
ReplaySubject
앞서 발행된 최신 데이터 n개(3)를 구독할 수 있다.
const { ReplaySubject } = rxjs
const subject = new ReplaySubject(3) // 마지막 3개 값 저장
subject.subscribe((x) => console.log('A: ' + x))
subject.next(1)
subject.next(2)
subject.next(3)
subject.next(4)
subject.next(5)
subject.subscribe((x) => console.log('B: ' + x))
subject.next(6)
subject.next(7)
<console>
“A: 1”
“A: 2”
“A: 3”
“A: 4”
“A: 5”
“B: 3”
“B: 4”
“B: 5”
“A: 6”
“B: 6”
“A: 7”
“B: 7”
AsyncSubject
앞서 발행된 내용이 있다고 하더라도 complete() 되는 시점에만 마지막 발행을 구독할 수 있다.
const { AsyncSubject } = rxjs
const subject = new AsyncSubject()
subject.subscribe((x) => console.log('A: ' + x))
subject.next(1)
subject.next(2)
subject.next(3)
subject.subscribe((x) => console.log('B: ' + x))
subject.next(4)
subject.next(5)
subject.subscribe((x) => console.log('C: ' + x))
subject.next(6)
subject.next(7)
subject.complete()
<console>
“A: 7”
“B: 7”
“C: 7”
Subject와 BehaviorSubject 비교
Subject는 구독자가 있을 경우에 발행된 값을 즉시 전달하지만 BehaviorSuject는 발행된 마지막 값을 저장해둔 후에 다음 구독자에게 전달한다.
Subject와 ReplaySubject 비교
발행될 때마다 전달하는 것은 똑같지만 최근 데이터 n개만큼 반환한다는 차이점이 있다.
활용하는 방법
1. 값이 발행되는 시점을 특별하게 해야하는 경우 사용할 수 있다.
BehaviorSubject : 초기값을 설정해야할 때, 마지막 값을 전달하고 싶을 때 ex) 접속시간 측정
ReplaySubject : 최근값을 n개 만큼 전달하고 싶을 때
AsyncSubject : complete() 시점에만 값을 전달하고 싶을 때
2. 함수형 프로그램에서 지양하는 변수를 대신하여 사용할 수 있다.
프로젝트에 적용하는 방법
1. Grid에서 다음 페이지의 row 데이터를 가지고 올때
페이지를 이동하게 되면 API를 재요청하여 해당 페이지를 구성할 데이터를 불러온다. 이때 페이지를 이동할 때마다 API를 요청하는데 API 요청을 subject로 subscribe한다.
서버에서 Grid 데이터를 받아 올 때 max, offset, list, totalCount를 받아온다.
- max : 한 페이지 당 row 개수
- offset : row의 첫번째 index 값
- list : row 데이터 리스트
- totalCount : 총 데이터 개수
2. Gird에서 sorting 할 때
row 데이터를 sorting하게 되면 해당 페이지의 데이터(max) 뿐만 아니라 전체 데이터(totalCount)에서 sorting을 해야하기 때문에 다시 한번 API 요청을 하게되는데 이때도 subject로 subscribe할 수 있다.
3. Header에 데이터의 개수를 표시할 때
헤더에 데이터 개수를 표시하려고 할 때 이 데이터가 업데이트 될 때마다 데이터 카운트를 변경해야하는데 이때 데이터를 subject로 subscribe 할 수 있다.