RxJS

빵동·2023년 5월 3일

rxjs

목록 보기
1/1

리액티브 프로그래밍

  • 비동기프로그래밍 패러다임의 하위 개념으로 이벤트나 배열같은 데이터 스트림을 비동기로 처리해 변화에 유연하게 반응하는 프로그래밍 패러다임
  • 데이터 스트림변화의 전달
    배열 : 정적인 데이터 스트림
    이벤트 이미터 : 동적인 데이터 스트림

리액티브 프로그래밍에서는 c=a+b 이후에 a를 변경하면 c도 변경된다. c는 계산 함수이기 때문에 a의 값을 변경해서 입력하면 새로운 값이 출려되는 것.

리액티브 프로그래밍은 근본적으로 좋은 응답성을 유지하고자 하는 목표가 있다.

이벤트 스트림을 옵저버블이라는 객체로 표현한다.
이벤트 처리를 위한 다양한 연사자를 제공하며 함수형 프로그래밍 기법도 도입되었다.

풀링방식의 데이터스트림을 구독하는 푸시 방식으로 전환한다.


keyword : 옵저버패턴, 명령형 프로그래밍, 함수형 프로그래밍, 순수함수

서브젝트는 옵저버를 등록하거나 해제할 수 있다.
등록한 서브젝트에 어떤 변화가 일어나면 notify를 통해 옵저버들에게 이벤트 발생을 알릴 수 있다.


명령형프로그래밍에 익숙하다면 async/await방식으로 비동기처리 가 좀 더 편할 것이다.

하지만 Rxjs는 비동기로 처리하는 여러 값을 함수형 프로그래밍 패러다임으로 다룬다.

FirstClass라는 개념은 함수를 인자로 사용하거나 함수 자체를 리턴하거나 함수를 변수에 할당 할 수 있다는 것이다.

함수를 일반적인 변수처럼 사용한다는 것.


옵저버블

옵저버패턴에서 완료와 에러에 대한 메서드를 추가한 것이다.

iterable과 iterator를 obserable과 observer로 명명한 것이다.

옵저버블은 특정 객체를 관찰하는 옵저버에게 여러 이벤트나 값을 보내는 역할을 한다. 옵저버블 객체 안에서 여러개의 값이나 이벤트를 취급하고, 옵저버의 함수를 호출해 필요한 값이나 이벤트를 보내는 방식이다.

옵저버블에는 4가지 개념이 있다.
하나의 값이나 이벤트를 다루는 싱글
여러개의 값이나 이벤트를 다루는 멀티플
데이터를 받을지 결정하는 풀
데이터를 보낼지 결정하는 푸시

이것들의 조합으로 4가지 개념들이 존재한다.

싱글멀티플
내 기준 데이터를 처리하기 위해 외부의 것을 함수이터레이터
내 기준 데이터를 처리해야 한다고 외부에서 푸시프로미스옵저버블

여러개 값을 보낼지 결정하는 개념이다.

생산자함수이터레이터프로미스옵저버블
소비자func.calliter.nextpromise.then옵저버

풀 방식은 데이터를 소비하는 쪽이 능동적으로 데이터를 호출하고 데이터를 생산하는 쪽은 데이터를 소비하는 쪽의 영향을 받는다.

푸시 방식은 데이터를 생산하는 생산자가 주체이다.
이벤트나 값 같은 데이터를 생산하는 쪽에서 준비되면 데이터를 소비하는 소비자에게 할려주는 방식이다.

그래서 프로미스든 옵저버블이든 생산자가 능동적으로 데이터를 생산하면 알림을 받을 수 있는 콜백이 있는 것이다.

프로미스는 객체를 생성하는 시점에,
옵저버블은 subscribe함수를 호출하여 값이나 이벤트를 소비할 수 있는 시점에 데이터를 생산한다.
그리고 생산한 데이터는 옵저버에 있는 콜백을 이용해 받을 수 있다. 이는 데이터를 소비하는 쪽에서 데이터를 생산하는 쪽을 제어 할 수 없다는 것이다.

풀 방식인 함수는 함수 선언만으로 아무런 일도 하지 않는다.
푸시 방식인 프로미스는 객체 생성과 동시에 값을생산하는 동작을 실행한다는 점이 다르다. 데이터 생성이 끝나야 값을 발행할 수 있다.

옵저버블은 데이터 생산자가 능동적으로 값을 푸시해 옵저버를 호출한다.


옵저버블 라이프 사이클

생성-> 구독 -> 실행 -> 해제

생성 : observerable.create, range, of
(생성된 옵저버블 인스턴스).pipe() <- 해당 pipe함수에 다양한 연산자를 인자로 사용해서 새로운 옵저버블 인스턴스를 생성 할 수 있다.

구독과 실행 : 데이터를 전달할 콜백을 제공해 함수를 호출한 후 옵저버블에서 발행하는 값을 사용하는 것으로 설명 할 수 있다.
subscribe함수를 사용한다.

함수를 여러번 호출해도 해당 함수가 각각 독립적으로 동작하는 특징이 있다.

즉 옵저버가 구독하는 이벤트에 이벤트가 발생하면 모든 옵저버가 같은 결과를 전달받도록 여러 옵저버에 멀티캐스팅 했다는 뜻이다.

옵저버블 객체 생성 자체는 아무 일도 하지 않는다. 어떤 일을 해야할지에 관한 정보만 있고 subscribe함수를 호출해야 옵저버블이 옵저버에 데이터를 전달하며 동작을 수행한다.

구독해제를 꼭 해줘야 메모리에 남아있는 옵저버블 객체를 해제 할 수 있다.


서브젝트는 멀티캐스팅을 지원하는 객체이다.

멀티캐스팅을 지원한다는 것은 여러 옵저버가 이벤트 변경이나 값 전달을 관찰하도록 옵저버블을 구독한 뒤 실제 이벤트 변경이나 값 전달이 됬을때 이를 알린다는 뜻이다.

구독중인 모든 옵저버가 호출되어 같은 값을 전달 받는다.

즉 subscribe함수로 여러 옵저버를 등록한 후 next로 발행하는 값을 여러 옵저버에 줄 수 있다.

서브젝트는 옵저버블이면서 옵저버 역할도 한다.

const { Subject } = require('rxjs');

const subject = new Subject();

subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`),
});

subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`),
});



subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);
subject.next(5);

연산자

연산자는 기본적으로 함수형태다.

파이퍼블연산자
<옵저버블인스턴스>.pipe(연산자1(), 연산자2) ...)
각 연산자를 거치며 새로운 옵저버블 인스턴스를 리턴한다.
<옵저버블인스턴스>.pipe(연산자1()).pipe(연산자2)) 형식도 동일한 결과를 갖는다.

배열.map.map.map은 배열을 총 3개를 더 생성한다. 메모리적으로 불리
옵저버블은 어떻게 동작할지 정의만 해놓은 것이고 구독 전까지 아무 동작이 일어나지 않다고 한번에 실행된다.

RxJS는 이벤트를 위한 로대시로 생각하자


순수함수와 연산자의 관계

입력된 값이 데이터(액션에 영향을 받지 않는)라면 Rxjs의 연산자도 순수함수다. map도 마찬가지다. 하지만 연산자 자체가 순수함수더라도 그 내부에서 호출하는 함수가 순수함수가 아니라면 액션이 되는 것이다.

Rx는 함수형 반응형이 아니다.

FRP라고 하면은 시간에 따라 연속적으로 변하는 특징이 존재해야하는데 rx는 불연속적이다.
FRP를 정의할 때의 기준에는 rx는 부합하지 않는다.

목적과 필요에 따라 FRP를 해야할 때가 있다.

예를 들어 동시에 일어난 사건이 있을떄 RX는 옵저버가 등록된 순서에 따라 동작이 달라진다. 이때문에 시간을 엄격하게 지켜 동작이 실행되지는 않는다.

동시에 일어나야할 일들이 실제 동시에 일어나는 것이 아니라 등록된 차례로 실행하는 것 뿐이다.

이런 시간에 관련한 부분은 FRP에서 좀 더 효율적인 방식으로 해결한다.


비동기처리
console.log('Before subscribe');

of(1, 2, 'a', 'b', 3, 4, ['aa', 'nn'], asapScheduler).subscribe(
  (x) => console.log(x),
  (err) => console.log(err),
  () => console.log('complete'),
);

console.log('After subscribe');

Before subscribe
After subscribe
1
2
a
b
3
4
[ 'aa', 'nn' ]
complete

From

from함수는 옵저버블로 변환할 수 있는 객체를 옵저버블로 변환해준다.
from함수에서 지원하는 데이터 타입의 객체는 다음과 같다
1. 옵저버블
2. 배열
3. 프로미스
4. 이터레이터
5. 문자열
6. 배열유사타입 ()

0개의 댓글