몇일 전에 요즘 내가 쓰고 있는 책의 초안을 일부를 공개하기로 셀프 선언한 이후, 사실 너무 바빴다 ㅠㅠ
1부 탈고일이 좀 남았지만… 마음이 급하다.
지인과는 과감히 탕수육 내기도 했으니. 더 급하다.

처음이니깐 간단히 책소개만 해보면.

RxJS가 무엇을 위해 준비된 라이브러리인지에 대한 답을 구하는 책이다. 더불어 RxJS의 활용법도 학습하는 책이다. 참고로 rxjs5 기준으로 쓰고 있다

오늘 소개할 부분은
웹어플리케이션 개발시 발생할 수 있는 입력 오류를 RxJS는 어떻게 접근했는지에 대한 이야기이다.


웹어플리케이션의 입력 데이터

웹어플리케이션의 동작 과정을 되돌아보면 사실 몇 개의 큰 과정으로 나눌 수 있다.

간단한 게시판을 예로 생각해보자.
게시판은 서버에 저장된 글을 보여주는 목록화면과 게시글의 내용을 보여주는 상세화면으로 구성되어 있다.
서버로부터 저장된 글에 대한 정보를 받고, 받은 정보를 바탕으로 화면과 관련된 UI작업을 한다.
게시글의 종류나 카테고리를 셀렉트 박스로 표현할 수도 있고, 작성된 글의 내용 일부를 화면에 표현하기도 한다.

또한 사용자가 게시글을 등록. 수정하는 편집화면도 있다. 편집화면에서는 사용자가 셀렉트 박스를 선택하기도 하고, 글을 입력하기도 한다. 사용자의 입력이 잘못된 경우에는 사용자에게 메시지를 전달하기도 하기도 한다.
글의 작성 및 수정이 끝나면 등록한 정보를 서버에 저장한다.

이 과정을 데이터가 흐르는 관점으로 살펴보면

    1. 목록화면과 조회화면은 서버로부터 데이터를 불러와 브라우저에게 전달한다.
    1. 브라우저에 전달된 정보를 브라우저의 UI객체에 전달한다.
    1. 편집화면은 브라우저 UI객체를 통해 사용자 입력정보를 전달받고 이를 다시 브라우저의 다른 UI객체나 브라우저 객체에 전달한다.
    1. 사용자가 작성한 정보를 브라우저 UI객체나 브라우저 객체를 이용하여 서버로 전달한다.

이 과정을 다시 상태머신 관점에서 살펴보자.
1)과 2)의 과정에서 입력값은 서버로부터 전달 받은 게시글 데이터가 된다. 두 과정의 입력값이 동일 할지라도 입력값을 받는 브라우저와 브라우저 UI 객체는 서로 다른 시점에 입력값을 전달받는다.
예를 들어 1)과정이 Ajax로 JSON 데이터를 받아와 브라우저의 객체로 저장하는 경우라면 Ajax는 비동기(Asynchronous) 호출로 데이터를 받기 까지 시간이 걸린다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// XMLHttpRequest에 의해 입력된 데이터
let result;
const xhr = new XMLHttpRequest();
xhr.onload = function(e) {
/*
* Ajax를 통해 얻은 데이터를 result 변수에 저장한다.
*
* {
* list: [
* "게시글1번. 안녕하세요.",
* "게시글2번. 반갑습니다.",
* "게시글3번. RxJS에 대해 알아봐요."
* ]
* }
*/
result = JSON.parse(xhr.responseText);
};
xhr.open("GET", url);
xhr.send();

반면, 브라우저 UI객체는 이미 브라우저에 존재하는 JSON 데이터를 받기 때문에 동기(Synchronous) 호출로 바로 결과 데이터를 얻을수 있다.

1
2
3
4
5
<ul>
<li></li>
<li></li>
<li></li>
</ul>
1
2
3
4
Array.from(document.querySelectorAll("li")).forEach((v, i) => {
// Ajax의 결과인 result 변수를 이용하여 DOM에 정보를 표현한다.
v.innerText = result.list[i];
});

마찬가지로 3)과 4)의 과정도 입력값은 사용자의 입력이 되지만, 전달된 입력값을 처리하는 시점은 상황에 따라 각각 다르다.

앞에서 설명한 내용을 간단히 정리하면 다음과 같다.

과정 데이터 데이터 흐름 전달 시점 예제
1) 게시글 서버 -> 브라우저 비동기 Ajax 통신으로 JSON 데이터를 받는다.
2) 게시글 브라우저 -> 브라우저 UI 객체 동기 JSON 데이터를 UI에 반영한다.
3) 사용자가 입력한 내용 사용자 -> 브라우저 UI객체 비동기 <textarea>를 통해 사용자 입력을 받는다.
4) 사용자가 입력한 내용 브라우저 UI 객체 -> 브라우저 -> 서버 동기, 비동기 <textarea>에 있는 데이터를 JSON 객체로 저장 후, 서버로 Ajax 요청을 한다

입력 데이터의 전달 시점이 다양하다.

앞에서 살펴본 바와 같이 입력데이터가 같을지라도 실제 각 객체들 사이로 데이터가 전달되는 시점은 다르다. 어떤 상황에서는 동기(Synchronous) 방식으로 데이터를 주고 받고, 어떤 상황에서는 비동기(Asynchronous) 방식으로 데이터를 주고 받는다.
이런 구조는 비단 웹어플리케이션 뿐만이 아니다. 소프트웨어 전반적으로 이와 같은 상황이 발생한다.
이런 이유는 두 방식의 차이점을 살펴보면 보다 명확히 알수 있다.

동기(Synchronous)

동기방식은 작업이 들어온 순서에 맞게 차근차근 하나씩 진행되는 것을 의미한다. 호출하는 함수가 호출되는 함수의 작업 완료를 기다린 후 그 다음을 진행하는 방식이다. 이 방식의 장점은 순차적으로 진행되기 때문에 개발이 쉽다. 반면, 처리하는 작업이 많을 경우에는 전체 작업 속도가 느려진다. 특히, 웹브라우저와 같이 단일 UI쓰레드를 사용하는 경우에는 해당 작업이 끝날때까지 브라우저는 대기하고 있어야만 한다.

이벤트가 아닌 동기(Synchronous) 방식인 함수호출도 시간이라는 개념을 도입하면 다음과 같이 표현될 수 있다.

결국 동기와 비동기는 시간의 축으로 봤을때는 같은 형태인 것이다.
또한, 이런 형태는 시간을 인덱스로 둔 컬렉션으로 생각할 수도 있다. RxJS에서는 이를 스트림(Stream)이라 표현한다.

RxJS에서는 이런 Stream을 표현하는 Observable 클래스를 제공한다.

Observable

Observable은 시간을 인덱스로 둔 컬렉션을 추상화한 클래스이다.
이 클래스는 동기나 비동기의 동작 방식으로 전달된 데이터를 하나의 컬렉션으로 바라볼 수 있게 해준다.
이렇게 함으로써 개발자는 데이터가 어떤 형태로 전달되는지에 대해 더이상 고민할 필요가 없어진다.
단지, Observable을 통해 데이터를 전달 받기만 하면 된다.

Observable의 표준화

RxJS의 Observable은 Rx에서 만든 라이브러리이기도 하지만, ECMAScript에 표준으로 제안된 스펙이기도하다.
https://github.com/tc39/proposal-observable

이 책에서 다루는 RxJS5는 ECMAScript에 제안된 표준 스펙을 기반으로 작성된 라이브러리이다.

모든 데이터는 Observable로 만들 수 있다.

Observble은 모든 데이터를 다룬다.

  • 키보드를 눌러서 입력된 데이터
  • 마우스를 이동하거나 클릭해서 입력된 데이터
  • Ajax/fetch 요청을 통해 얻은 데이터
  • Web socket을 통해 전달된 데이터
  • Message를 통해 전달된 데이터