이전 글에서
ReactiveX는 Observer 패턴을 Iterator 패턴과 결합 하고 함수형 프로그래밍을 컬렉션과 결합하여 이벤트 시퀀스를 관리하는 이상적인 방법에 대한 요구 사항을 충족합니다.
인 이유를 공식 웹페이지의 예시를 조금 변형하여
먼저 함수형 프로그래밍과 컬렉션의 결합으로 설명하고자 한다.
공식 웹 페이지에는 함수형 프로그래밍을 사용하지 않는 예시를 들었는데,
let count = 0;
document.addEventListener('click', () => console.log(`Clicked ${++count} times`));
만약 순수 함수 형태로 작성한다면 아래와 같을 것이다. StackBlitz에서 보기
function scan(accumulator, seed, callback) {
let _seed = seed;
return function (value, args) {
_seed = accumulator(_seed, value);
callback(_seed, args);
};
}
document.addEventListener(
'click',
scan((count) => count + 1, 0,
(count) => console.log(`Clicked ${count} times`)
)
);
이를 RxJS에서는 아래와 같이 해결할 수 있을 것이다.
import { fromEvent } from 'rxjs';
import { scan } from 'rxjs/operators';
fromEvent(document, 'click')
.pipe(scan(count => count + 1, 0))
.subscribe(count => console.log(`Clicked ${count} times`));
위와 같은 과정으로 함수형 프로그래밍을 사용하여 표현한다면 StackBlitz에서 보기
import { throttle } from 'throttle-debounce';
function scan(accumulator, seed, callback) {
let _seed = seed;
return function (value, args) {
_seed = accumulator(_seed, value);
callback(_seed, args);
};
}
document.addEventListener(
'click',
throttle(
1000,
scan(
(count) => count + 1,
0,
(count) => console.log(`Clicked ${count} times`)
)
)
);
와 같이 표현할 수 있을 것이다.
마지막으로 중간에 전달하는 인수를 바꾸어야 한다면? StackBlitz에서 보기
import { throttle } from 'throttle-debounce';
function scan(accumulator, seed, callback) {
let _seed = seed;
return function (value, args) {
_seed = accumulator(_seed, value);
callback(_seed, args);
};
}
function map(accumulator, callback) {
return function (value) {
callback(accumulator(value));
};
}
document.addEventListener(
'click',
throttle(
1000,
map(
(event) => event.clientX,
scan(
(count, clientX) => count + clientX,
0,
(count) => console.log(`Clicked ${count} times`)
)
)
)
);
와 같이 표현할 것이다. (만약 Pure JavaScript에서 더 좋은 방법을 알고 있다면 댓글로 알려주시면 감사하겠습니다)
이런 복잡함을 RxJS에서는 함수형 프로그래밍과 컬렉션(중첩된 연산자, 체이닝)의 결합으로 간결하고 명확하게 다루었다고 생각한다.
다음에는 Observer 패턴과 Iterator 패턴의 결합에 대한 생각을 풀어보고자 한다.