꼬프로

Categories

2부 Chapter 01. RxJS란 무엇인가?

1.1. RxJS란?

RxJS는 Observable을 사용하여 비동기 및 이벤트 기반 프로그램을 작성하기 위한 라이브러리

  • 비동기 컬렉션 데이터를 다루는 라이브러리

1.2. RxJS 시작하기

1.2.1. RxJS 첫 번째 예제

  • 페이지를 클릭했을 경우 event.currentTarget 정보를 콘솔로 출력
const eventHander = event => {
	console.log(event.currentTarget);
};
document.addEventListener('click', eventHander);
  • 이벤트 핸들러를 만들고
  • 핸들러를 addEventListener를 통해 등록

  • 동일한 기능을 RxJS로 작성
  • 이벤트를 Observable로 변환하는 fromEvent 함수를 제공
  • Observable의 subscribe 메소드를 이용하면 observer가 Observable을 구독할 수 있음
  • Observable에서 전달된 데이터를 observer가 소비
const { fromEvent } = rxjs;
const click$ = fromEvent(document, 'click') // Observable
const observer = event => {
	console.log(event.currentTarget);
};
click$.subscribe(observer);
  • 이벤트 핸들러 -> observer
  • addEventListener -> subscribe
  • 이벤트 정보를 Observable로 변환하는 작업이 추가 됨

  • RxJS는 다양한 모듈 타입에서 사용이 가능 - 자세히보기

1.2.2. RxJS 첫번째 예제 개선하기

  • 실제 우리가 필요한 정보는 click이 아니라 click 될 때의 currentTarget 정보
  • pluck 오퍼레이터를 이용하면 이 의도를 더욱 코드에 명확히 나타낼 수 있음

pluck(properties:…string):Observable
pluck은 사전적으로 ‘~을 뽑다’라는 의미
추출할 속성들을 문자열로 지정

  • RxJS에서 오퍼레이터를 적용하기 위해서는 반드시 pipe 오퍼레이터를 통해 적용
  • pipe 오퍼레이터는 파라미터로 전달된 오퍼레이터들이 적용된 새로운 Observable 인스턴스를 반환

pipe(operations:…):Observable
RxJS 5.5 부터 적용된 오퍼레이터, 처리해야 할 작업(operator)들을 순차적으로 받아서 처리
5.5까지는 도트 체이닝을 사용 했으나 6.0 부터는 pipe 오퍼레이터만 제공
오퍼레이터를 적용하기 위해서는 반드시 pipe 오퍼레이터를 사용
6.0에서 도트 체이닝을 사용하려면 rxjs-compat 모듈을 추가로 사용

// 도트체이닝 방식
ajax$
	.switchMap(data => ...)
	.filter(user => ...)
	.map(user => ...);
// pipe 오퍼레이터
ajax$
.pipe(
	switchMap(data => ...),
	filter(user => ...),
	map(user => ...)
);
  • 다음 코드는 pluck 오퍼레이터를 사용하여 코드의 의도를 더욱 분명하게 변경한 예
const { fromEvent } = rxjs;
const { pluck } = rxjs.operators;
const currentTarget$ = fromEvent(document, 'click')
.pipe(
	pluck('currentTarget')
); // Observable
const observer = currentTarget => {
	console.log(currentTarget);
};
currentTarget$.subscribe(observer);
  • click이 발생하면 currentTarget$은 event 객체의 currentTarget을 전달
  • observer는 currentTarget$을 구독함으로서 currentTarget 데이터를 전달 받음

1.2.3. RxJS 두 번째 예제

  • 동기적인 작업을 RxJS로 구현
  • 사용자 정보 배열에서 촉나라 사람만 추출
  • array의 filter 메소드를 통해 원하는 사용자만 추출
const users = [
	{
		name: '유비',
		birthYear: 161,
		nationality: '촉'
	},
	{
		name: '손권',
		birthYear: 182,
		nationality: '오'
	},
	{
		name: '관우',
		birthYear: 160,
		nationality: '촉'
	},
	{
		name: '장비',
		birthYear: 168,
		nationality: '촉'
	},
	{
		name: '조조',
		birthYear: 155,
		nationality: '위'
	},
	{
		name: '손권',
		birthYear: 182,
		nationality: '오'
	}
].filter(user => user.nationality == '촉');
const log = user => console.log(user);
users.forEach(log);
  • 동일한 기능을 RxJS로 작성
  • Array -> from 메소드
const { from } = rxjs;
const { filter } = rxjs.operators;
const users$ = from([
	{
		name: '유비',
		birthYear: 161,
		nationality: '촉'
	},
	{
		name: '손권',
		birthYear: 182,
		nationality: '오'
	},
	{
		name: '관우',
		birthYear: 160,
		nationality: '촉'
	},
	{
		name: '장비',
		birthYear: 168,
		nationality: '촉'
	},
	{
		name: '조조',
		birthYear: 155,
		nationality: '위'
	},
	{
		name: '손권',
		birthYear: 182,
		nationality: '오'
	}
]).pipe(
	filter(user => user.nationality == '촉')
);
const observer = user => console.log(user);
users$.subscribe(observer);
  • log -> observer
  • forEach -> subscribe
  • Array 객체를 Observable로 변환, pipe를 이용하여 filter 오퍼레이터를 적용

1.3. RxJS 4대 천왕

RxJS의 중요 개념

  • Observable
  • 오퍼레이터
  • Observer
  • Subscription
  • Subject
  • Scheduler

이 장에서는 중요한 4가지, Observable / 오퍼레이터 / Observer / Subscription 개념을 집중적으로 살펴 봄

1.3.1. Observable

  • 시간을 축으로 연속적인 데이터를 저장하는 컬렉션을 표현한 객체
  • Observable은 데이터를 제공하는 소스를 Observer에게 전달 - 스트림

1.3.2. 오퍼레이터

  • Observable을 생성 및 조작하는 함수
  • Observable을 생성하기도 하고 연결하기도 하며 분리하거나 합치기도 함
  • 오퍼레이터는 현재의 Observable 인스턴스를 기반으로 항상 새로운 Observable 인스턴스를 반환

1.3.3. Observer

  • Observable에 의해 전달된 데이터를 소비하는 주체
  • Observer는 next, error, complete 함수 객체를 가르킴
  • next : 데이터가 전달될 때 호출
  • error : 에러가 발생했을 때 호출
  • complete : 데이터 전달이 완료됐을 때 호출
  • subscribe 메소드를 통해 Observable과 연결

Observable.prototype.subscribe
subscribe는 Observer를 파라미터로 받음

  • Observer 객체를 전달하는 subscribe 사용 예
const observer = {
	next: x => console.log('Observer가 Observable로 부터 받은 데이터:' + x),
	error: err => console.log('Observer가 Observable로 부터 받은 에러 데이터:' + err),
	complete: () => console.log('Observer가 Observable로 부터 종료되었다는 알림을 받은 경우')
}
click$.subscribe(observer); // observer 객체를 파라미터로 받음
  • next 콜백 함수를 전달하는 subscribe 사용 예
click$.subscribe(x => console.log('Observer가 Observable로 부터 받은 데이터:' + x));
  • next, error, complete 콜백 함수를 전달하는 subscribe 사용 예
// observer의 next, error, complete 함수를 파라미터로 받음
click$.subscribe(
	x => console.log('Observer가 Observable로 부터 받은 데이터:' + x),
	err => console.log('Observer가 Observable로 부터 받은 에러 데이터:' + err),
	() => console.log('Observer가 Observable로 부터 종료되었다는 알림을 받은 경우')
);

1.3.4. Subscription

  • Observable.prototype.subscribe의 반환값
  • 등록된 Observable의 데이터를 더이상 받고 싶지 않을 때는 unsubscribe 메소드를 호출하여 자원을 해제

// ...
const subscription = currentTarget$.subscribe(observer);
// unsubscribe으로 자원 해제가 가능
subscription.unsubscribe();

1.4. RxJS 개발 방법

예제를 RxJS의 4가지 개념으로 표현하면 다음과 같음

  • 이벤트를 Observable로 변환
  • pluck, fliter 오퍼레이터를 이용하여 데이터를 변경
  • 데이터를 처리할 Observer를 만들고
  • Observable의 subscribe 메소드를 통해 Observer를 등록

RxJS를 사용해서 개발할 경우의 프로세스

  1. 데이터 소스를 Observable로 변경
  2. 오퍼레이터를 통해 데이터를 병합, 추출, 분리, 나눔
  3. 원하는 데이터를 받아 처리하는 Observer를 만듬
  4. Observable의 subscribe를 통해 Observer를 등록
  5. Observable 구독을 정지하고 자원을 해지