RxJS 빠르게 배우기 02 - Observables
지난 글에서 RxJS로 코드를 짰을 때 어떤 느낌인지 살짝 확인 했다. 이제는 핵심적인 개념들과 실제로 어떻게 구현 되어 있는지 등을 하나씩 확인해보자.
옵저버 패턴과 옵저버블 (Observable)
Rx의 개념은 옵저버 패턴을 확장한 것이라고 알려져잇다. 그렇다면 옵저버 패턴은 뭘까? 쉽게 설명하자면 관찰의 역할을 하는 옵저버 객체들을 서브젝트라는 객체에 등록한 다음, 서브젝트 객체의 상태 변경이 일어나면 notify()
를 호출해 알리게 되는 구조이다.
위키 문서 이미지
자바스크립트에서는 가장 대표적으로 EventListener
를 예시로 들 수 있다.
옵저버블 타입은 ReactiveX에서 기존 옵저버 패턴에서 데이터가 없다는 것을 알리는 complete
메서드, 에러가 발생했음을 알리는 error
메서드가 추가된 것이라고 한다. RxJS는 옵저버 패턴을 적용한 Observable
을 중심으로 동작한다. Observable
객체는 객체 안에서 여러 값이나 이벤트를 취급하고, 옵저버의 함수를 호출해 필요한 값이나 이벤트를 보내는 역할을 한다.
Observable
이 사용되는 예시를 간단하게 확인해보자.
아래 코드는 subscribe 될 때 1, 2, 3 값을 즉시 (동기적으로) 밀어넣는 Observable
이다. 그리고 값 4는 1초 뒤에 subscribe 호출로 값이 들어가고, 그 다음 완료된다.
1 | import { Observable } from "rxjs"; |
Observable
을 호출하고 값들을 보기 위해서는 subscribe
를 해야 한다.
1 | import { Observable } from "rxjs"; |
위 코드는 콘솔에 아래와 같은 결과를 보여준다.
1 | Just before subscribe |
Pull vs Push
Pull
, Push
라고 하는 것은 데이터를 만들어내는 쪽 (Producer)과 데이터를 소비하는 쪽 (Consumer) 사이에 어떻게 커뮤니케이션 하는가를 설명해주는 두 프로토콜이다. 먼저 Pull
프로토콜을 사용하는 경우에는 Consumer가 데이터를 언제 받을지를 결정하는 시스템이다. Producer는 데이터가 언제 Comsumer에게 전달될지를 알 수 없는 상태로 있는다.
모든 자바스크립트 함수는 기본적으로 Pull
시스템을 따르고 있다. 함수는 Producer라고 볼 수 있고, 해당 함수를 호출하는 코드는 호출한 결과로 하나의 리턴 값을 받는 “pulling“을 한 것이라고 볼 수 있다.
ES2015는 generator 함수들과 iterators를 소개하고 있다. 이것들은 다른 타입의 Pull
시스템을 따르고 있다. iterator.next()
를 호출하고 있는 코드는 Consumer라고 할 수 있고, 그 Consumer는 다양한 값들을 이터레이터(Producer)로부터 받을 수 있게 된다.
Pull
방식이 익숙한 방식임을 알게 되었고, 그렇다면 Push
는 그 반대겠지?
Push
시스템에서는 Producer가 Consumer에게 언제 데이터를 보내줘야 할지를 결정하게 된다. 반대로 Consumer는 데이터를 언제 받게 되는지를 알지 못하는 상태로 있는다.
Promise
는 가장 일반적인 Push
시스템이라고 볼 수 있다. 자바스크립트를 알고 있다면 무슨 느낌인지 알 수 있기 때문에 디테일한 설명은 생략한다.
Observable
과 function
의 차이는 뭘까? Observable
은 다수의 값을 시간 흐름에 따라서 리턴할 수 있다는 것이다. 쉽게 말하자면 함수는 아래와 같은 동작을 지원하지 않는다.
1 | function foo() { |
반면 Observable
는 아래와 같은 것이 가능하다.
1 | import { Observable } from "rxjs"; |
아래와 같이 나타난다.
1 | 42 |
subscribe는 next 값이 소진될 때까지 map이 도는 것과 유사하게 동작하는 것 같다. 이 부분은 그냥 여러 값을 리턴하는 것처럼 동작할 수 있군 하면서 넘어가면 될 것 같다.
정리해보자면, 여러 값을 내보낼 수 있는가? 또는 하나의 값만 내보낼 수 있는가?의 기준과 Pull 방식을 따르는가? Push 방식을 따르는가?의 기준으로 설명할 수 있다. 해당 기준으로 나누면 아래와 같다고 볼 수 있다.
Push | Pull | |
---|---|---|
단일 | Promise |
Function |
복수 | Observable |
Iterable |
옵저버블에 대한 자세한 내용
Obeservable
이 맡는 관심사는 다음과 같다.
Observable
생성Obeservable
구독Obeservable
실행Obeservable
처리 (구독 취소)
생성
Observable
생성자는 subscribe
함수 하나를 인자로 받는다.
아래 예시는 hi
문자열을 매 초마다 subscriber
에게 전달하는 코드이다.
1 | import { Observable } from 'rxjs'; |
일반적으로는
new Observable
을 사용해 만들 수 있지만,of
,from
,interval
등 생성 함수들을 이용해 보통 만들어진다.
구독과 실행
구독은 데이터를 전달할 콜백을 제공해 함수를 호출하는 것
이라고 볼 수 있고, 실행은 Observable에서 발행하는 값을 사용하는 것
이라고 설명할 수 있다. 구독은 subscribe
함수를 이용한다.
1 | const observable = new Observable(function subscribe(subscriber) { |
new Observable(function subscribe(subscriber) { ... })
는 구독이 발생하는 시점부터 실행되는 내용이다. Observable
의 실행에서 전달할 수 있는 값의 타입은 세 가지이다.
Next
알림: 특정 값을 전달해준다.Error
알림: 자바스크립트의 에러 또는 예외를 전달한다.Complete
알림: 값을 보내지 않는다.
Next
타입은 핵심적인 데이터라고 볼 수 있고, 나머지 두 가지는 실행 중 한 번만 발생하게 되는 것들이다. Next
는 무한으로 보낼 수 있지만, 나머지 두 개가 발생하고 나서는 값을 전달할 수 없게 된다.
subscribe
메서드를 통해서 next()
메서드로 전달받는 값을 처리하는 콜백을 넣을 수 있다. complete
메서드가 실행되면 구독은 끊어지고, 이후 값이 전달되지 않게 된다.
구독 취소
구독 취소는 Observable
의 구독을 해제하는 것이다. subscribe
메서드를 호출하면 리턴 값으로 Subscription
객체를 리턴한다.
1 | const subscription = observable.subscribe(console.log); |
이 객체는 진행중인 실행을 나타내고, 최소한의 실행 취소를 위한 API를 가지고 있다.
1 | import { from } from 'rxjs'; |
만약 create()
- (아마 과거에 Observable.create()
함수를 말하는 것 같다. 현재 문서에서는 new Observable(function subscribe(subscriber) {...}))
형태로 모두 바뀌었다. - 블로그 주인)를 사용한 경우에는 커스텀한 unsubscribe
함수를 리턴해줘야 한다.
1 | const observable = new Observable(function subscribe(subscriber) { |
Reference
- RxJS 프로그래밍 (책)
- https://rxjs-dev.firebaseapp.com/guide/observable
RxJS 빠르게 배우기 02 - Observables