## Redux-Saga Channel 이란 Redux-Saga에는 다양한 Effect들이 있다. `put`과 `take`를 이용하면 Redux Store와 통신할 수 있고 `call` 이펙트를 이용하면 HTTP Request를 기다렸다가 받을 수 있다. 여기까지만 하더라도 일반적인 어플리케이션을 개발하는데 문제는 없다. 그런데 Websocket과 같이 주기적 (또는 특정한 이벤트가 발생했을때) 외부와 통신을 하려면 어떻게 해야 하는가. 위와 같은 질문으로 인해 Redux-Saga에 `channel` 이라는 개념이 추가 되었다. 초기에 channel이라는 개념 없이 Redux-Saga에서 Webosocket과 같은 이벤트를 다루기 어려웠던 이유는 두개가 이벤트에 반응하는 방식이 달라서 였다. ``` javascript // Websocket에서 이벤트를 처리하는 방식 const socket = new WebSocket(); socket.onmessage((msg) => console.log(msg)); // Redux-Saga에서 이벤트를 처리하는 방식 function* handleEvent() { const someData = yield call(getSomeData); } ``` 위와 같이 Websocket 같은 경우 서버에서 이벤트가 들어오면 반응하는 방식이지만, Redux-Saga는 이벤트를 발행하여 값을 가져오는 방식으로 동작한다. 한마디로 `push`와 `pull`형식으로 서로 다르게 동작하고 있는 것이다. 그렇다면 Redux-Saga에서 이벤트를 가져오려 할때 값이 없으면 기다렸다가 다시 가져오는 식으로 동작하면 되지 않을까 라는 생각이 들 수도 있다. 그러나 그러한 방식은 몇가지 단점이 있다. - 값이 없을 경우를 대비해야 하기 때문에 불필요한 검사 조건이 항상 들어간다. - 값이 들어왔을때 바로 반응하지 못할 확률이 있다. - 데이터의 정합성과 무결성이 지켜지지 못할 확률이 있다. 좀 더 매끄럽고 데이터를 안전하게 보호하기 위한 방법으로 `channel` 개념이 추가되었다. [Channel](https://en.wikipedia.org/wiki/Channel_(programming))은 프로세스간 메시지 통신을 **동기적**으로 수행하기 위한 방법을 말하는데 안전하게 데이터를 전달받을 수 있도록 해주는 것이다. Go가 대표적인 channel 개념을 도입한 언어이다. [Redux-Saga의 공식문서](https://redux-saga.js.org/docs/api/)에서는 이렇게 설명하고 있다. > channle은 task간의 메시지를 주고받기 위한 오브젝트 이다. 보낸 메시지를 관심있는 Receiver가 요청할때까지 메시지는 대기하고 해당 메시지가 사용할 수 있을때까지 Receiver는 대기한다.\ 원문) *A channel is an object used to send and receive messages between tasks. Messages from senders are queued until an interested receiver request a message, and registered receiver is queued until a message is available.* 따라서 채널에는 메시지를 보관하기 위한 Buffer가 필요하며 채널을 생성할때 같이 설정해 준다. 이제 간단한 예제와 함께 Redux-Saga에서 사용할 수 있는 channel을 알아보도록 하겠다. ### Task를 순차적으로 처리하는 방법 ``` javascript import { fork, delay, takeEvery } from "redux-saga/effects"; function* root() { yield takeEvery(SOMEACTION, watcher); } function* watcher() { yield fork(request); } function* request(delayTime: number) { // Something... } ``` 위 예시에서 어떠한 Action이 일어날때마다 `watcher` saga가 실행되는데, 이때 특정한 작업을 수행하도록 되어있다. `takeEvery`는 Action이 일어날때마다 수행 되기 때문에 몇번이고 요청을 할 수 있다. 이때 만약, 해당 작업들이 **순차적**으로 수행되어야 한다고 가정할때 위의 동작은 우리가 의도한대로 동작할까. 우리의 기대와는 달리 동작들은 순차적이 아니라 작업이 먼저 끝난 순서대로 동작한다. 이때 순차적으로 작업을 수행하기 위해 `actionChannel`을 사용할 수 있다. ``` javascript export function* watcher() { const requestList = yield actionChannel(SOMEACTION, buffers.sliding(1)); while (true) { yield take(requestList); yield call(request); } } function* request() { // Something... } ``` 이런식으로 `actionChannel`을 생성하여 `channel`을 `take`해서 순차적으로 처리를 할 수 있다. ### 외부 이벤트와 연결하는 방법 외부 이벤트와 연결하는 방법에는 `eventChannel`을 이용한 방법이 있는데 자세한 내용은 [이곳](https://uzihoon.com/post/604ab3a0-73d8-11ea-8c78-39f3eadbf977)에서 다루었기 때문에 설명은 제외하도록 하겠다. ### 결국 Channel이란 개념은 어떻게 이벤트를 처리하느냐에서 나왔다. React 어플리케이션 또한 상호작용을 해야하며 그러한 이벤트들이 사용자와의 상호작용도 있지만 서버와의 상호작용 또한 중요하게 작동한다. Redux-Saga에서는 이러한 이벤트 처리를 원래 설계한 목적대로 수행하기 위해 Channel이라는 개념을 도입했고 해당 개념을 이해하고 적절하게 사용한다면 Saga에서 추구하는 디자인 패턴에 맞춰서 이벤트를 쉽게 핸들링 할 수 있을 것이다.