리액티브 프로그래밍?

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

정적인 데이터 스트림 : 배열
동적인 데이터 스트림 : Event Emitter

데이터 스트림 안에 어떤 값이 변했을 때의 전달이 바로 이루어짐

명령형 프로그래밍에서느
c = a+ b를 실행한 후
a값이 바뀐다면 a만 바뀔 뿐 c 값이 같이 바뀌지 않는다.
하지만 리액티브 프로그래밍에서는 a값이 바뀌었을때 c값도 변한다.

옵저버블

옵저버블: 객체
옵저버블 라이프 사이클 : 생성, 구독, 실행, 구독해제

특수한 메서드가 있어요. subscribe,
이 함수는 인자로 함수는 세개 전달해요.
next, error, complete

subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
형태는 이렇습니다.

옵저버블은 멀티캐스팅 안됨. -> 뒤늦게 구독해도 클릭이벤트가 발생하면 같은 내용을 전달 받아야 하는데 그렇지 않다. -> 서브젝트를 이용

옵저버블과 옵저버
옵저버블에 subscribe가 호출되야 옵저버블과 observer가 연결해 실행됌.
실행된 결과는 옵저버블의 next가 실행되면서 확인할 수 있다.

옵저버의 complete나 error함수를 호출할때까지 next함수로 값을 발행해요.

const { Observable } = require('rxjs');
const observableCreated$ = Observable.create(function(observer) {
console.log('BEGIN Observable');
observer.next(1);
observer.next(2);
observer.complete();
observer.next(3);
console.log('END Observable');
});

observableCreated$.subscribe(
function next(item) {console.log(item);},
function error(e) {},
function complete() { console.log('complete');}
);
옵저버는 next, error, complete 함수로 구성된 객체에요.

observer가 Observable을 구독한다?

구독 해제

subscription.unsubscribe(); -> observable의 return function() {...} 호출됌.

Promise도 함수나 Observable과 같이 then을 호출할 때마다 동일한 값을 받을 수 있다.
동작방식은 함수나 Observable과 다름.

그 이유는 Promise는 Observable 함수와 다르게 정의부가 생성 시 딱 한 번 호출되고, 상태(resolve,rejec)가 결정되면 변경되지 않기 때문.

Observable은 Promise와 다르게 next, error, complete의 상태를 가진다. 여러 개의 데이터를 보낼 수 있기 때문에 Promise와 다르게 complete 상태가 존재함.

자바스크립트 비동기 처리 과정과 RxJS Scheduler

이벤트루프, nodejs 비동기 처리 과정 자세히 나온 레퍼런스

레퍼런스 : http://sculove.github.io/blog/2018/01/18/javascriptflow/

RXJS 스케줄러는 RxJS에서 자바스크립트의 비동기 작업을 효과적으로 처리할 수 있도록 도와주는 역할을 한다.
RxJS 스케줄러를 잘 활용하려면 -> 자바스크립트 엔진이 어떻게 비동기 작업을 처리하는지 이해하면 RxJS Scheduler를 사용하는데 많은 도움이 될거다.

자바스크립트 엔진

자바스크립트 엔진은 기본적으로 하나의 스레드 (실행 줄기)에서 동작해요.
하나의 스레드 - 하나의 스택(stack)
하나의 스레드 - 하나의 스택이란 말은 동시에 단 하나의 작업을 하는거에요.
요것이 무슨말인가?

https://meetup.toast.com/posts/89
토스트 기술 블로그에 단일 호출 스택과 Run-to-Completion
부분을 보면 이해에 도움이 되요.

정말 간단히 이해하고 있는 바를 설명하면, 수행되는 코드 덩어리는 무조건 함수로 묶여요. main함수든, 직접 생성한 일반 함수든
그 함수들은 스택에 쌓여요. 즉 코드 덩어리가 스택에 쌓이는 겁니다. 그리고 그 쌓인 코드들이 순서대로 pop되면서 실행되는 구조에요.

요약하면

코드 ( 동기적인 실행, 이벤트 ) -> 자바스크립트 V8엔진 (콜스택) -> web apis (브라우저가 제공합니다) -> event loop -> 자바스크립트 V8엔진 (콜스택)

자바스크립트 동작 구조를 따라가다가 애매한 부분이 call stack에서 pop된 func() 즉 소스코드가
v8 엔진을 통해 다음과 같은 과정을 통해 코드가 머신에서 실행된다고 때려맞췄다. 이 부분에 대해서는
고수분들에게 여쭤봐야겠다.

https://hackernoon.com/javascript-v8-engine-explained-3f940148d4ef

우리가 사용하는 자바스크립트가 동작하는 구조를 설명해 놓은 다이어그램

https://medium.com/@gaurav.pandvia/understanding-javascript-function-executions-tasks-event-loop-call-stack-more-part-1-5683dea1f5ec

이벤트 루프는 비동기 코드들의 큐에요. 이 이벤트 루프는 콜스택( 동기적인 코드가 수행되고) 콜스택이 비어있을때 큐에서 하나씩 빼서 콜스택에 넣고, 그러면 콜스택에서 pop되고 비동기 코드들이 수행되겠죠.

그래서 맨날 비동기적인 코드들이 동기적인 코드보다 실행이 늦게 뜨는거에요.

webapi가 뭐냐 하실 수 있는데, ajax 요청을 클라이언트에서 서버로 합니다. 요런 일들 누가해주죠? 코드가 해주는데 이거 동작하게 해주는 코드가 web-api라고 때려맞췄습니다.

이벤트루프 참고 : nodejs의 내부 동작 원리 (libuv, 이벤트루프, 워커쓰레드, 비동기) -빨간색코딩

unsubscribe을 어떻게 처리하나?

Angular 라이프사이클에서 보통 ngOnInit에서 서버로부터 데이터를 읽어옴.
그러면 angular의 HttpClientModule의 경우 Observable 타입으로 리턴을 해주기 때문에
subscribe를 통해 데이터를 접근할 수 있다는..

그리고 subscribe한 것을 ngOnDestroy에서 unsubscribe를 해줘야하는데,

꽤 마음에 드는 방법이 있어서 정리함.
이 블로그를 보면 Async pipe를 쓰면 컴포넌트가 destroyed 될때 messageSubs$ 이가 자동으로 unsubscribe 된다고 합니다~

export class AsyncPipeCardComponent implements OnInit {
  messageSubs$: Observable<string>;
  constructor(private upperCaseService: UpperCaseService) {}
 
  ngOnInit() {
    this.messageSubs$ = this.upperCaseService.getUpperCaseMessage();
  }
}
<h4 class="card-title">{{messageSubs$ | async}}</h4>

Async pipe, take등 여러가지 방법이 있음.

레퍼런스

https://web-front-end.tistory.com/71

https://blog.codecentric.de/en/2018/01/different-ways-unsubscribing-rxjs-observables-angular/

https://levelup.gitconnected.com/auto-unsubscribing-in-angular-components-like-a-pro-742220b01d0c

rxjs mock api
https://blog.angular-university.io/rxjs-switchmap-operator/

더 더 상세한 자바스크립트 비동기 처리 과정

coming soon...

todo

html 렌더링하고, 자바스크립트 순서~

DOMContentLoaded

비동기 처리 순서 맞춰보기


async wrappedLoading(callback) {
    this.loadingEnabled = true;
    console.log(2);
    await callback();
    console.log(6);

    this.loadingEnabled = false;
  }

this.wrappedLoading(() => {
      return new Promise((resolve, reject) => {
        this.selectDataById({id}).subscribe((result) => {
		  ...
          console.log(3);

          resolve();
        });
      });
    });

    console.log(4);

    this.wrappedLoading(() => {
      return new Promise((resolve, reject) => {
        this.selectDataById({pwpId: id}).subscribe((result) => {
          ...
          console.log(5);

          resolve();
        });
      });
    });

순서
2
4
2
3
6
5
6

Subject

Subject : Observable + Observer

그리고 Subject는 multicast, Observable은 unicast

출처: https://arnoldyoo.tistory.com/18 [Arnold's life]

rxjs operator

rxjs marble

이동

fromEvent

Rxjs는 DOM 이벤트를 Observable로 변환하는 fromEvent 함수를 제공함.
fromEvent는 Observable를 생성하는 공통 함수들과 RxJS에서 사용하는 클래스들이 존재하는 rxjs 네임스페이스에 존재한다. Rxjs에서는 Observable의 subscribe 메서드를 이용하면 observer가 Observable를 구독할 수 있습니다.
fromEvent(target: EventTargetLike, eventName: string, selector: function): Observable

레퍼런스

pipe

RXJS에서 오퍼레이터를 적용하기 위해서는 반드시! pipe 오퍼레이터를 통하여 적용해야만 한다.
pipe 오퍼레이터는 파라미터로 전달된 오퍼레이터들이 적용된 새로운 Observable 인스턴스를 반환한다.

RXJS5.5 부터 적용된 오퍼레이터

pluck

pluck('프로퍼티명') observable에서 프로퍼티만 빼서 리턴함.

partition

filter 조건이 참인경우와 거짓인 경우에 대해서 Observable을 각각 분리하여 두 개의 크기를 가진 배열로 반환한다.
rxmarble

merge

Flattens multiple Observables together by blending their values into one Observable.
레퍼런스

flatMap(mergeMap), switchMap, ConcatMap

https://softwaree.tistory.com/30

Because concatMap does not subscribe to the next observable until the previous completes, the value from the source delayed by 2000ms will be emitted first.
Contrast this with mergeMap which subscribes immediately to inner observables, the observable with the lesser delay (1000ms) will emit, followed by the observable which takes 2000ms to complete.

concatMap
mergeMap
switchMap

scan

es6 reduce와 똑같음

scan

distinctUntilChanged

distinctUntilChanged

tap

전달된 값을 그대로 전달
tap

from

배열요소들을 Observable로 바꿀때
from

switchMap vs map

https://stackoverflow.com/a/57904241/7929206

switchMap: Maps values to observable. Cancels the previous inner observable.

map: Add projection with each value.

shareReplay

unsubscription하기 싫어서 take(1) 해버리면
같은 스코프에서 또 subscribe하는 경우 데이터를 읽지 못함.

import { Subject, ReplaySubject } from "rxjs";
import { pluck, share, shareReplay, take, tap } from "rxjs/operators";

// simulate url change with subject
const routeEnd = new Subject<{ data: any; url: string }>();
// grab url and share with subscribers
const lastUrl = routeEnd.pipe(
  tap(_ => console.log("executed")),
  pluck("url")
  // defaults to last 1 value
  // shareReplay()
);
// requires initial subscription
const initialSubscriber = lastUrl.subscribe(console.log);
// simulate route change
// logged: 'executed', 'my-path'
routeEnd.next({ data: {}, url: "my-path" });
// logged: 'my-path'
const lateSubscriber = lastUrl.pipe(take(1)).subscribe(console.log);

const lastSubscriber = lastUrl.subscribe(console.log);

레퍼런스:
learn RxJs - https://www.learnrxjs.io/learn-rxjs/operators/multicasting/sharereplay#examples

profile
서로 아는 것들을 공유해요~

0개의 댓글