요즘 함수형 프로그래밍 혹은 리액티브 프로그래밍 같은 용어가 자주 보인다.
이 문서에서는 Reactive 혹은 함수형 프로그래밍에 대한 설명을 깊게 하진 않는다.
왜냐면 설명하자니 너무 어렵다. 그치만 중요하다 개인발전을 좋아하는 개발자라면 꼭 한번 찾아서 읽어보자
ReactiveX 또는 리액티브 프로그래밍 대한 정보는 나프콘 2016 김훈민님의 발표내용 또는 김훈민님 블로그에서 자세히 확인이 가능하니 여기서는 ReactiveX에 대해서만 간략하게 알아보자
공식홈페이지에는 아래와 같이 설명되어있다.
ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.
이 내용을 해석하면
ReactiveX는 observable 시퀀스를 사용하여 비동기 및 이벤트 기반 프로그램을 작성하기위한 라이브러리입니다.
처음 ReactivX는 .NET용 라이브러리로 출시되었으며, 그이후 RxJS / RxJava / Rx++ 등 추가로 출시하면서 오픈소스화 하였다고한다
ReactiveX 시리즈의 JavaScript 구현체 라이브러리가 RxJs
지원 브라우저 현황은 아래와 같다.
IE6+, Chrome 4+, FireFox 1+, Node.js v0.4+
Angular 2(이하 Angular)에서 비동기 처리등에 적극 도입했으며, Angular의 필수 라이브러리 중 하나이다.
ReactiveX는 비동기의 문제를 해결하기 위해 만들어졌는데, promise / await / generator 등과 무엇이 다르며, 도대체 어떠한 방향으로 해결하고자 했을지 알아보자
위에 문장은 Rx의 창시자인 Erik Meijer가 한 얘기로 Rx에서 비동기 처리를 위해 시간이라는 개념을 도입했다.
아래의 그림을 보면 마우스로 발생되는 이벤트들을 시간이라는 개념으로 표시해두었다.
[그림출저 Erik Meijer의 Twitter]
우리가 일반적으로 알고있는 데이터베이스는 메모리 혹은 디스크 공간에 저장되는 데이터 집합이다. 근데 마우스가 데이터베이스라면 데이터에 해당하는 것은 무엇일까? 바로 이벤트다. Rx는 이 이벤트조차 데이터로 취급하는거다. 그 이벤트를 시간이라는 배열(컬렉션)에 담아, 아래와 같은 형태로 관리를 한다.
Mouse[click, click, move, move, move]
이것을 스트림(Stream)라고 표현한다.
Rx에는 이러한 개념에 LINQ(Language Intergrated Query)를 도입했다.[LINQ도 에릭 마이어가 만들었다.] LINQ는 통합 질의 언어로 코드에서 데이터를 가져올때 SQL문처럼 표현할 수 있도록 도와주는 일종의 언어 확장이다.
제공하는 방식으로는 SQL 방식과 메서드 방식이 있다. Rx에서는 메서드 방식을 도입했다.
간단한 예시로 아래를 보자
먼저 SQL 방식이다.
var productName = from product in products
where product.id == 1
select product.name;그 다음은 메서드 방식이다.
var productName = products
.Where(product => product.id == 1)
.Select(product => product.name);그럼 Rx에서는 LINQ를 어떻게 활용하고 있는지 보자.
var button = document.getElementById('submitBtn');
var clickStream = Rx.Observable.fromEvent(button, 'click');
clickStream
.filter(e => {
return e.altKey;
})
.subscribe(e => {
console.log(e.clientY);
});쿼리로 표현하면 이런식 아닐까 싶다.
SELECT clientY FROM clicks where altKey == true;- Observable: 미래의 값(value)나 이벤트의 호출 가능한 수집의 개념을 나타냄.
- Observer: Observable에 의해 전달 된 값을 처리하는 콜백 콜렉션.
- Subscription: Observable의 실행을 나타냄. 주로 실행 취소에 유용함.
- Operators: map, filter, concat, flatMap 등과 같은 method를 사용하여 컬렉션을 다루는 함수 프로그래밍 스타일을 가능하게하는 순수(pure) 함수.
- Subject: EventEmitter와 동일하며 여러 Observers에 값 또는 이벤트를 멀티 캐스팅함.
- Schedulers: 동시 처리를 제어하는 중앙 집중식 디스패처로서 계산이 언제 발생하는지 조정할 수 있다. setTimeout or requestAnimationFrame or others.
각각의 요소들에 대해 알아보자
Observable은 관찰할 수 있는 대상 혹은 데이터를 지칭합니다.
이 데이터는 ['Rxjs', 'RxJava'] 같은 배열 데이터도 될 수 있고 Ajax 비동기 통신 결과 혹은 클릭 이벤트 등 Observable로 만들 수 있습니다.
간단한 Observable 객체를 만들어보도록 하겠습니다.
const observable$ = Rx.Observable.create(function(observer) {
observer.onNext(1);
observer.onNext(2);
observer.onNext(3);
observer.onCompleted();
});
observable$.subscribe(observer);객체 observable$은 [1, 2, 3] 같이 표현할 수 있으며, 이러한 Observable를 관찰(구독)하는 대상을 Observer라고 합니다.
RxJs에선 observable$의 subscribe 메서드를 이용해서 Observer에 구독할 수 있습니다.
Observer는 아래처럼 정의되어있습니다.
interface Observer<T> {
closed?: boolean;
next: (value: T) => void;
error: (err: any) => void;
complete: () => void;
}- next: 다음 데이터를 불러올때 발생되는 메서드입니다.
- error: 데이터를 불러오는 과정에서 오류가 발생되었을때 발생되는 메서드입니다.
- complete: 모든데이터를 다 불러왔을때 발생되는 메서드입니다.
위에서 선언했던 observable$를 구독하여 observer$를 처리 해보도록 하겠습니다.
const observable$ = Rx.Observable.create(function(observer) {
observer.onNext(1);
observer.onNext(2);
observer.onNext(3);
observer.onCompleted();
});
const subscription = observable$.subscribe(
(value) => console.log(`값: ${value}`),
(error) => console.log(`에러: ${error}`),
() => console.log(`완료`)
);
//구독 취소
//subscription.unsubscribe();
//결과 console
//"값: 1"
//"값: 2"
//"값: 3"
//"완료"여기서 변수명 observable$ 변수 뒤에 $는 해당 변수가 스트림(stream) 혹은 Observable임을 나타내는 의미입니다.
observable를 구독하면 리턴값으로 Subscription이 생성되는데 위에 구성요소에 설명한거와 같이 unsubscribe() 메서드를 이용하여 구독을 취소에 사용됩니다.
observable$이 subscribe 메서드를 호출하여 구독시 Subscription 객체가 생성되며, 이 생성된 subscription의 unsubscription 메서드 호출시 구독 취소와 함께 사용되었던 리소스가 제거됩니다.
SubScription은 주로 구독을 취소하여 구독으로 발생된 리소스를 해제하는 할때 사용됩니다. angular에서는 ngOnDestroy에서 Observable를 폐기할때 사용합니다.
또한 add 메서드를 이용하여 하위 subscription을 포함시킬 수 있습니다. add로 추가된 하위 subscription은 상위 구독정보가 취소될 경우 같이 구독 취소됩니다.