본문으로 바로가기

rxjs-dev.firebaseapp.com/guide/subject

 

Subject는 특수한 종류의 Observable이자 Observer이다.

뭐가 특별한가? 값을 여러 Observer에게 멀티캐스팅해줄 수 있는 류의 옵저버블이다.

 

 

아래는 가장 간단하게 subject를 생성해본 것이다.

const subject$ = new Subject();
const obs = {
  next: (x) => console.log(x),
  error: () => console.log(error),
  complete: () => console.log("done"),
};

const subOne = subject$.subscribe(obs);

subject$.next(1);

const subTwo = subject$.subscribe(obs);

subject$.next(2);
subject$.complete();

// output
1
2 2
done done

 

위와 같은 단순한 Subject 외에 특별한 류의 Subject가 있습니다.

BehaviorSubject, ReplaySubject, and AsyncSubject.

 

 

1) BehaviorSubject

 

"최종값"을 기억했다가 옵저버에게 전달합니다.

말 장난같지만 최종값이란게 최초값이 될 수도 있습니다. 최초값주고 아무 동작 안하면 최초값이 최종값이 되는거니까요.

In the following example, the BehaviorSubject is initialized with the value 0 which the first Observer receives when it subscribes. The second Observer receives the value 2 even though it subscribed after the value 2 was sent.

 

이는 두 가지 의미가 있는데

 

1) 초기값을 설정해서 옵저버에서 초기값을 전달할 수 있습니다.

2) 옵저버를 추가하면, 마지막 값을 기반으로 자동으로 트리거 됩니다.

 

이게 뭔 말이냐구요? 한 번 코드로 보시죠.

import { BehaviorSubject } from 'rxjs';

const subject = new BehaviorSubject(0); // 0 is the initial value

subject.subscribe({
  next: v => console.log(`observerA: ${v}`),
});

console.log('==========1==========');
subject.next(1);
console.log('==========2==========');
subject.next(2);

subject.subscribe({
  next: v => console.log(`observerB: ${v}`),
});

console.log('==========3==========');
subject.next(3);

 

출력 결과는 아래와 같습니다.

 

observerA: 0
==========1==========
observerA: 1
==========2==========
observerA: 2
observerB: 2
==========3==========
observerA: 3
observerB: 3

 

즉, observer A는 초기값 0이 설정된 이후에 설정되었음에도 초기값을 가지고 트리거가 되며

observer B는 2라는 값이 주어진 이후에 설정되었음에도 2라는 값을 가지고 트리거가 됩니다.

 

 

2) ReplaySubject

 

subject의 별미같은 녀석입니다. 좀 독특하죠.

옵저버가 구독한 시점과 상관없이, 전체 방출된 값들을 전부 replay합니다.

 

import { ReplaySubject } from 'rxjs';
const subject = new ReplaySubject();

subject.subscribe({
  next: v => console.log(`observerA: ${v}`),
});

subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);

console.log('옵저버 B가 생겼으니 1, 2, 3, 4전부 replay ');
subject.subscribe({
  next: v => console.log(`observerB: ${v}`),
});

console.log('여기서부턴 다시 정상적으로');
subject.next(5);

observerA: 1
observerA: 2
observerA: 3
observerA: 4
옵저버 B가 생겼으니 1, 2, 3, 4전부 replay 
observerB: 1
observerB: 2
observerB: 3
observerB: 4
여기서부턴 다시 정상적으로
observerA: 5
observerB: 5

 

 

그런데 상식적으로, 방출된 값을 무한히 저장할 수도 없을테고, 메모리 문제가 생길 것이라고 예상할 수 있습니다.

이럴 경우에는 애초에 생성할 때 3가지 값만 저장하겠다고 ReplaySubject를 생성할 때 지정하면 됩니다.!

const subject = new ReplaySubject(3); // buffer 3 values for new subscribers

 

버퍼의 크기 뿐만 아니라, 시간 제한도 둘 수 있습니다. 아래 코드는 100만큼의 버퍼를 한계로 하되, 시간은 500ms로 가져갑니다.

500ms 지난 값은 버리겠다는 말이죠.

const subject = new ReplaySubject(100, 500 /* windowTime */);

 

 

3) AsyncSubject

 

의외로 간단한 subject입니다.

옵저버에게 전달된 마지막 값이 complete되었을 때만 딱 한 번 실행됩니다.

import { AsyncSubject } from 'rxjs';

const subject = new AsyncSubject();

subject.subscribe({
  next: v => console.log(`observerA: ${v}`),
});

// observerA 무반응
subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);

subject.subscribe({
  next: v => console.log(`observerB: ${v}`),
});

subject.next(5);

console.log('이제 complete할거임. 마지막 값이 5를 가지고 이제 출력 시작함');
subject.complete();

 

이제 complete할거임. 마지막 값이 5를 가지고 이제 출력 시작함
observerA: 5
observerB: 5


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체