1. 개요
Nest.js에서 Microservice를 구현하면서 RxJS개념을 사용이 되어 정확하게 이해하고자 정리를 합니다. 듣기로는 Angular에서 사용되는 개념이라고 하네요(Angular를 쓸 기회가 있을지는 모르겠지만...)
RxJS는 Reactive Extensions For JavaScript 라이브러리라고 해서 리액티브 프로그래밍을 javascript에서 지원하기 위해 만들어진 라이브러리입니다. 리액티브 프로그래밍이란 이벤트나 배열 같은 데이터 스트림과 전파를 중심으로 변화에 유연하게 반응하는 프로그래밍을 의미합니다.
이 리액티브 프로그래밍은 Push 시나리오 방식으로 외부와 통신합니다.
*Push 시나리오 : 외부에서 명령하면서 응답이 오면 그때 반응하여 처리함. 데이터를 가지고 오기 위해서 Subscribe를 해야 함.
RxJS는 이러한 비동기 이벤트 기반의 프로그램 작성을 돕기 위해 함수형 프로그래밍을 이용해 이벤트 스트림을 Observable이라는 객체로 표현합니다.
키워드 : RxJS, 리액티브 프로그래밍, 비동기 이벤트, 함수형 프로그래밍, Observable
위 키워드를 이해하고 있으면 RxJS를 이해할 수 있습니다.
2. Subscribe에 대한 이해
document.addEventListener('click', () => console.log('Clicked!'))
웹 프로그래밍을 하다보면 위와 같이 특정 엘리먼트를 클릭하면 console.log를 발생시키는 코드를 작성할 때가 있습니다.
이것을 이벤트를 처리한다고 말하며 위 코드는 비동기적(사용자가 클릭을 해야 동작하는)으로 동작합니다.
targetElement는 document이며, addEventListener를 사용해 click 이벤트를 구독했고, 사용자가 마우스로 클릭하기 전까지는 위 console.log는 동작하지가 않습니다.
이것은 Observer Pattern이 적용된 코드로 볼 수 있습니다.
*Observer Pattern: 객체의 상태변화를 관찰하는 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 들을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴
위 코드를 RxJS로 표현하면 아래와 같이 표현할 수 있습니다.
import {fromEvent} from 'rxjs'
const observable = fromEvent(document, 'click')
const subscriber = () => console.log('Clicked!')
observable.subscribe(subscriber)
1. fromEvent를 이용해서 이벤트를 observable 객체로 만듭니다.(1번 파라미터는 dom요소, 2번 파라미터는 click과 같은 이벤트)
2. subscriber(이벤트핸들러)를 정의합니다.
3. observable가 subscribe를 사용해 이벤트 핸들러인 subscriber을 구독하도록 합니다.
1줄로 표현할 수 있는 것을 3줄로 표현하는게 사실 가독성도 떨어지고 불편하기만 한데, RxJS를 사용하는 이유는 있습니다.RxJS는 비동기 코드가 많아질 경우 그만큼 제어의 흐름이 복잡하게 얽혀 코드를 예측하기가 어려워지는데 이러한 비동기 프로그래밍의 문제를 해결하는데 도움을 줍니다.
3. Observable
Observable 객체는 특정 객체를 관찰하는 이벤트 핸들러인 Subscriber에게 여러 이벤트나 값을 보내는 역할을 합니다.
const observable = new Observable(subscriber => {
subscriber.next(1)
subscriber.next(2)
subscriber.next(3)
setTimeout(() => {
subscriber.next(4)
subscriber.complete()
}, 1000)
})
console.log('just before subscribe')
observable.subscribe({
next(x) {
console.log('got value ' + x)
},
error(err) {
console.error('something wrong occurred: ' + err)
},
complete() {
console.log('done')
},
})
console.log('just after subscribe')
위 코드에서는 observable이 subscriber에게 연속으로 1,2,3을 푸시하고 1초 후에 4를 푸시하도록 되어있습니다.
Observer는 3개의 메서드가 있습니다.
1. next: Observable에게 데이터를 전달합니다.
2. complete: Observable에게 메서드의 실행이 완료되었음을 알립니다. next는 더 이상 데이터를 전달하지 않습니다.
3. error: Observable에게 에러를 전달합니다. 이후에 next와 complete 이벤트가 발생하지 않습니다.
라이프 사이클
- 생성 -> 구독 -> 실행 -> 구독해제
Observable은 이벤트를 동기 또는 비동기로 발생시킬 수 있음을 꼭 기억해야 합니다.
4. 연산자
javascript의 map, filter와 같은 선언형 메소드처럼 RxJS에서도 Observable에 대해 연산메소드를 지원합니다.
pipe: pipe(연산자1(), 연산자2(), ...)
연산자를 연결해서 호출할 수 있습니다. 각 연산자를 거치면서 새로운 Observable 인스턴스를 리턴합니다.
observableCreated$.pipe(
map(function(value) {
return logAndGet(value, value * 2);
}),
map(function(value) {
return logAndGet(value, value + 1);
}),
map(function(value) {
return logAndGet(value, value * 3);
}),
toArray()
).subscribe(function(arr) {
console.log('arr', arr);
});
of: 나열된 인자를 순차적으로 next하는 Observable 인스턴스를 리턴합니다.
of( 10,20,30).subscribe({
next: console.log,
error: console.error,
complete: () => console.log('완료')
});
range: 범위 내 수의 값들을 전달하는 Observable 만들 때 사용합니다.
range(1,3).subscribe(
(value) => console.log(`next ${value}`),
(err) => console.log(`err ${value}`),
(value) => console.log(`complete`)
)
// next 1
// next 2
// next 3
// complete
fromEvent: 브라우저에서 발생하는 Event를 Observable로 바꿀 때 사용합니다.
fromEvent(document.getElementById('app'), 'click').subscribe(
(v) => console.log(v.currentTarget),
(err) => console.log(err),
() => console.log('complete)
)
firstValueFrom: Observable을 구독하고 Observable에서 첫 번째 값이 도착하자마자 promise를 반환하여 Observable을 promise로 변환합니다.
import { interval, firstValueFrom } from 'rxjs';
async function execute() {
const source$ = interval(2000);
const firstNumber = await firstValueFrom(source$);
console.log(`The first number is ${ firstNumber }`);
}
execute();
// 예상 출력 :
// '첫번째 숫자는 0'
자주 사용되는 연산자가 있으면 또 추가하겠습니다!
참고
https://pks2974.medium.com/rxjs-%EA%B0%84%EB%8B%A8%EC%A0%95%EB%A6%AC-41f67c37e028
https://min9nim.vercel.app/2020-04-24-rxjs/
https://chifuyu.tistory.com/31
'FrontEnd > ES&JS 문법' 카테고리의 다른 글
[Javascript] 호이스팅이란? (0) | 2022.10.17 |
---|---|
[Typescript] 자주 쓰는 문법 정리 (1) | 2022.09.08 |
[Javascript] 클로저(Closure) 요약 (0) | 2022.04.21 |
[ECMAScript] Javascript ES6 Spread, Rest 정리 (0) | 2021.12.10 |
[ECMAScript] Javascript ES6 기초 문법 정리 (0) | 2021.11.11 |