redux-saga 캡쳐

React는 MVC패턴에서 V(View)를 담당하고 있습니다.

앱이 가벼운 경우에는 State로 데이터를 핸들링 할 수 있지만,

앱이 커질 경우에는 데이터 관리를 별도로 해야하는 요구사항이 생기게됩니다.

이때 사용할 수 있는 것이 Redux와 MobX 등, 상태 관리 라이브러리입니다.

 

redux-saga는 redux의 액션 생성자와 reducer의 순수성을 유지하고 사이드 이펙트를 처리하기 위해 사용합니다.

여기서 사이드 이펙트는 부작용을 발생시키는 어떠한 효과가 아니라,

데이터 요청이나 비동기 작업, 브라우저 캐시 같이 순수하지 않은 작업들을 의미합니다.

 

 

Redux-Saga란?

redux-saga는 리덕스의 미들웨어입니다.

리덕스가 액션을 수행하면 redux-saga에서 디스패치하여 redux의 액션을 가로챈 뒤, 액션의 역할을 수행 하고

다시 액션을 발행하여 데이터를 저장하거나 다른 이벤트를 수행시킵니다.

redux-saga 동작 이미지 출처 uzihoon.com/post/181be130-63a7-11ea-a51b-d348fee141c4

 

redux-saga와 비슷한 라이브러리로 redux-thunk가 있지만,

redux-saga는 redux-thunk에 비해 이펙트 함수를 통해 다양한 작업들을 처리할 수 있습니다.

redux-saga가 좀 더 러닝커브가 높습니다.

  • 비동기 작업 시 기존 요청 취소 처리 가능
  • 특정 액션 발생 시 다른 액션이 디스패치 되도록 할 수 있음
  • 웹 소켓 사용 시 channel 기능을 사용하여 효율적 코드 관리가 가능
  • API 요청이 실패 했을때 재 요청하는 작업을 할 수 있음

이 외에도 다양한 비동기 작업들을 처리 할 수 있습니다.

 

 

자주 사용하는 헬퍼 함수

redux-saga는 스토어에 지정된 액션들이 디스패치되었을 때,

task를 만들기 위해 내부 함수들을 감싸는 헬퍼 이펙트를 제공합니다. 

 

all

제너레이터 함수를 배열의 형태로 인자로 넣어주면 병렬로 동시에 실행됩니다.

이때 모든 함수에 대한 결과가 resolve될 때까지 블럭됩니다. 

 

put

특정 액션의 디스패치하도록 합니다.

결과를 스토어에 디스패치(put) 합니다.

 

call, apply

순수 객체만 리턴하는 함수입니다. 오브젝트 메소드 호출을 지원합니다.

첫번째 파라미터는 함수이며 나머지 파라미터는 해당 함수에 넣을 인수 값 입니다.

액션이 발생하면 전달한 함수를 호출하여 실행합니다.

API가 리턴될때까지 블럭되며, 비동기 함수 호출 시 용이합니다.

call과 apply는 두번째 인자 값의 차이만 있습니다.

 

delay

설정된 시간 이후에 resolve를 하는 Promise 객체를 리턴합니다.

제너레이터를 정지하는데 사용할 수 있습니다.

 

takeEvery

액션이 발생하게되면 task를 실행합니다.

task가 종료되기 전에 또 다른 액션이 발생할 경우, 또 하나의 새로운 task를 실행합니다.

 

takeLatest

액션이 발생하게되면 task를 실행합니다.

만약 실행 중인 task가 있다면 기존 task를 종료하고 새로운 task를 실행합니다.

실수로 여러번 클릭했을때를 방지하거나 마지막에 요청된 데이터를 보여줄 때 사용합니다.

 

takeLeading

액션이 발생하게되면 task를 실행합니다.

해당 task의 실행이 완료되기 전까지 뒤에 오는 이벤트들을 블럭합니다.

이후 task가 완료되면 액션에 대해 수신합니다.

 

throttle

초 이내 요청을 한 번만 보냅니다.

마지막 함수가 호출된 후 일정 시간이 지나기 전 재 호출하지 않습니다.

스크롤 이벤트 사용 시 용이합니다.

 

debounce

초 이내 요청을 한 번만 보냅니다.

처음 함수나 마지막 함수만 호출 후 일정시간이 지나기 전 재 호출하지 않습니다.

 

 

제너레이터함수

ES6에 포함된 제너레이터 함수는 function* 키워드로 작성합니다.

redux-saga는 이 제너레이터 함수를 적극 활용한 사례입니다.

제네레이터는 제네레이터함수의 반환이며 redux-saga가 작성한 함수를 호출하여 반환받는 객체가 제너레이터입니다.

*이터레이터 프로토콜과 이터러블 프로토콜을 준수합니다.

// 코드출처: https://mskims.github.io/redux-saga-in-korean/basics/DeclarativeEffects.html 
import { takeEvery } from "redux-saga/effects"
import Api from "./path/to/api"

function* watchFetchProducts() {
  yield takeEvery("PRODUCTS_REQUESTED", fetchProducts)
}

function* fetchProducts() {
  const products = yield Api.fetch("/products")
  console.log(products)
}

yield를 이용하여 이펙트들을 호출하고 수행된 내용을 다시 돌려 받아 그 액션을 수행합니다.

redux-saga는 제네레이터를 통해 이펙트를 수행하는 역할을 합니다.

 


참고, 출처

이터러블 (Iterable)

순회가능한 객체를 말합니다. 

순회 가능한 객체는 Symbol.iterator 심볼 속성을 가지고 있으며 이터레이터 객체를 반환하는 객체를 말합니다.

이러한 것을 이터러블 프로토콜이라고 하며 이터러블 객체라고 합니다.

 

이터레이터 (Iterator)

이터러블 메소드로 반환하는 객체입니다.

next 메소드를 구현하고 있으며 value, done을 반환하는 객체입니다.

반환되는 IteratorResult는 {done: boolean, value: any} 형태의 단순한 객체입니다.

next 메소드를 통해 모든 값을 돌고 나면 done이 true로 나오며 끝납니다.

한번 끝난 이터레이터는 다시 돌아가지 않으며 value가 undefined로 리턴합니다

이러한 것을 이터레이터 프로토콜이라고 합니다.

 

for of 루프는 순회 시작 전 [Symbol.iterator]() 메소드를 호출하여 이터레이터 객체를 얻습니다.

그 후에 순차적으로 next 메소드를 호출하며 하나씩 순회합니다.

보통 이터러블 프로토콜과 이터레이터 프로토콜을 하나의 객체에 모두 구현하는 것이 일반적입니다.

// 영원히 0을 반환하는 무한 이터레이터 예시
var zeroesForeverIterator = {
    [Symbol.iterator]: function () {
        return this;
    },
    next: function () {
        return {done: false, value: 0};
    }
};

 

사용자 이터레이터 객체 생성

이터러블 프로토콜은 obj[Symbol.iterator]: Function => Iterator로 표현할 수 있습니다.

그 후 이터레이터 프로토콜을 따라 value, done가 들어있는 오브젝트를 반환하는 next 메소드를 가진 객체를 반환하면 됩니다. 

const iterable1 = {};

iterable1[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

console.log([...iterable1]); // Array [1, 2, 3]

 

제너레이터 (Generator)  

이터러블, 이터레이터 객체를 만드는 손 쉬운 방법입니다.

동작은 function* 문법을 사용해서 작성하며 next를 통해 실행합니다.

next 메소드를 통해 실행이 되며 yield 문을 만나면 정지합니다. 

next 메소드를 호출함으로써 값을 소비할 수 있습니다. 

function* 문법을 통해 함수가 생성되고 최초로 호출될때 함수 내부의 어떠한 코드도 실행되지 않습니다.

이때 생성자 함수가 반환되는데 이것을 제너레이터 함수라합니다. 그 후 값을 소비하며 함수로 부터 반환되는 객체를 제너레이터라고 합니다.

 

즉, 제너레이터 객체는 이터레이터 객체입니다. 

(이터레이터 프로토콜을 따르고 있습니다.)

 

예시

값이 더이상 업을 경우 value: undefined, done: true가 반환된 것이 확인됩니다.

function* generatorFunc() {
  yield 1;
  yield 2;
  yield 3;
}

const it = generatorFunc();

console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

 

제너레이터 적극 활용한 예로 redux-saga가 있습니다.

 

 

 

 


 

참고 및 정의 출처

자바스크립트는 단일 스레드입니다.

단일 스레드라는 것은 하나의 스택이라는 뜻으로 동시에 하나의 일만 가능하다는 것을 의미합니다.

 

하지만,

자바스크립트가 사용되는 환경을 보면 비동기 작업을 통해 여러개를 동시에 처리하고 있는것 같습니다. 

멀티 스레드라고 착각할 수도 있을 것 같은데,

어떻게? 이렇게 동작할 수 있는지를 알아보도록 하겠습니다.

 

 

자바스크립트 엔진

메모리 힙(Memory Heap)과 콜 스택(Call Stack)으로 이루어져 있습니다.

  • 메모리 힙
    • 구조화되지 않은 넓은 메모리 영역을 말한다.
    • 객체들이 할당된다
      • 프로그램에 선언한 변수, 함수 등
  • 콜 스택
    • 함수 호출은 프레임들의 스택을 형성
    • 먼저 들어온 것이 나중에 나가는 선입 후출

 

자바스크립트 엔진에는 설명하려는 이벤트 루프가 등장하지 않는데, 이유는 간단합니다.

비동기 작업에서 필요한 중요한 요소인 이벤트루프, 콜백 큐등은 자바스크립트를 구동시키는 환경(=브라우저, 노드)이 담당하고 있기 때문입니다.

 

 

브라우저 환경

출처: https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

 

  • Web APIs
    • 브라우저에서 제공하는 API들, 웹 브라우저에 내장되어 있다
      • DOM, Ajax, Timeout 등..
      • 브라우저 및 주변 컴퓨터 환경의 데이터를 노출하고 이를 사용하여 유용한 복잡한 작업을 수행 할 수 있다
  • Callback Queue
    • 처리할 메시지 목록인 메시지 대기열
    • 먼저 들어온 것이 먼저 나가는 선입선출
      • Task Queue
        • ex: setTimeout
      • Micro Task Queue (= Job Queue) 
        • ex: Promise의 .then()
      • Animation Frames
        • ex: requestAnimationFrame API
  • Event Loop
    • 콜 스택과 콜백 큐를 감시한다
    • 콜 스택이 비어있으면 콜백 큐에서 태스크를 가지고 와서 콜 스택에 추가하는 행동을 한다

+ Event Table: 특정 이벤트가 발생했을때 어떤 콜백함수가 호출되어야하는지 알고 있는 자료구조

 

 

크롬 기준

Micro Task Queue > Animation Frames > Task Queue 순으로 실행됩니다.

그 외에 Queue들도 설명하는 블로그 글도 있기는 하나 정확한 정보는 못 찾았다고 합니다.

도움이 되는 글이라 생각하니 방문해서 읽어보세요~

velog.io/@thms200/Event-Loop-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84#animation-frames

 

Event Loop (이벤트 루프)

이번 글은 Event Loop (이벤트 루프) 에 대해 정리해보려고 한다. Event Loop? Event Loop 출처 How JavaScript works: an overview of the engine, the runtime, and the call stack Event Loop는 MDN 문서로 검색하면 "큐의 다음 메시

velog.io

 

여튼 동작을 예로 들면.. 

ES6의 Promise의 then이 Micro Task Queue로 들어가며 setTimeout 함수는 Task Queue로 들어간다.

이때 Task Queue 대기열에 Task가 있어도 Micro Task Queue가 먼저 이벤트 루프에 의해 콜 스택으로 이동된다.

 

 

Micro Task Queue와 Job Queue는 같은 것 일까?

공부하던 중에 논란이 있음을 인지했고 찾아본 두 블로그 글을 가져와봅니다.

정확한 설명은 링크를 통해 들어가서 확인해보세요^^

 

ECMA에선 PromiseJobs라는 내부 큐(internal queue)를 명시합니다.

V8 엔진에선 이를 '마이크로태스크 큐(microtask queue)'라고 부르기 때문에 이 용어가 좀 더 선호되고 있습니다.

- ko.javascript.info/microtask-queue

 

브라우저마다 프라미스의 호출 순서가 다른 문제를 지적했다.

프라미스가 ECMAScript에 정의되어 있는 반면에 마이크로 태스크는 HTML 스펙이 정의되어 있는데,

둘의 연관관계가 명확하지 않기 때문이다.

ES6부터 프라미스를 위해 잡 큐(Job Queue)라는 항목이 추가되었지만, HTML 스펙의 마이크로 태크스와는 별도의 개념이다.

프라미스A+ 스펙문서의 Note를 보면 구현 시에 일반(macro) 태스크나 마이크로 태스크 둘 다 사용할 수 있다고 적혀 있다.

실제로 프라미스가 처음 자바스크립트에 도입되는 시점에는 프라미스를 어떤 순서로 실행할 것인가에 대한 논의가 꽤 있었던 것으로 보인다.

하지만 앞서 언급한 것처럼 현재는 프라미스를 마이크로 태스크라고 정의해도 무리가 없을 것 같다.

- meetup.toast.com/posts/89

 

 


참고

ko.javascript.info/microtask-queue

meetup.toast.com/posts/89

 

프로그래밍의 관점을 갖게하고 결정하는 역할인 프로그램의 패러다임에 대해 알아보겠습니다.

발전하게 된 순서는 '절차적 -> 객체지향 -> 함수형'으로 단점들을 극복을 위해 나왔다고 합니다.

 

 

프로그래밍 패러다임

명령형 프로그래밍(How): 알고리즘을 명시하고 목표는 명시하지 않는다

  • 프로그램의 상태와 상태 변경을 시키는 '구문'의 관점에서 연산을 설명하는 방식
    • 절차적 프로그래밍: 수행되어야 할 연속적인 계산 과정을 포함하는 방식
    • 객체지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현
  • 선언형 프로그래밍(What): 알고리즘을 명시 하지않고 목표만 명시한다
    • 어떤 방식(How)가 아닌 무엇(What)과 같은지를 설명하는 방식
      • 함수형 프로그래밍: 순수함수를 보조함수와 조합하는 방식

 

 

명령형 프로그래밍

절차적 프로그래밍 (위키백과)

실행 절차에 중점을 둔 프로그래밍 방식으로 순차적인 처리방식으로 프로그램 전체가 유기적인 연결이 있다. 

순차적인 처리방식은 컴퓨터의 동작 방식과 같아서 처리 시간이 빠르다고 한다.

 

특징

  1. 하나의 큰 기능을 처리하기 위해 작은 단위의 기능들로 나누어 처리하는 Top-Down 방식
  2. 비교적 작은 규모의 작업을 수행하는 함수 생성
  3. 인수, 반환 값으로 명령을 전달하고 수행
  4. 데이터와 함수를 별개 취급
  5. 특정 기능을 수행하려면 해당 메소드를 직접 호출

 

장단점

장점

  • 개인 프로젝트에 적합
  • 객체 지향에 비해 빠르다

단점

  • 대형 프로젝트에 부적합
  • 유지보수가 어렵다
  • 코드 순서가 중욯서 순서 변경 시 다른 결과 초래 가능
  • 분석과 디버깅이 어렵다

 

 

객체지향 프로그래밍 (위키백과, 관련포스팅)

기능별로 모듈화하여 하드웨어가 같은 기능을 중복하지 않게하고 모듈을 재활용하여 하드웨어의 처리량을 줄인다.

'객체'라는 기본 단위로 나누고 이들의 상호작용으로 서술하는 방식

클래스를 이용해 연관있는 처리부분과(함수) 데이터부분(변수)을 하나의 객체(인스턴스)로 묶어 생성, 사용, 작은 문제를 해결하는 객체를 생성해 큰문제를 해결하는 Bottom-Up 방식.

네가지 특징(추상화, 캡슐화, 다형성, 상속)을 지키며 코딩해야하며 이 조건을 지키지 않고 클래스 단위로 프로그래밍하는 것은 객체지향이 아닌, 클래스기반(캡슐화)을 사용하는 것이다.  

 

특징

1. 추상화

현실세계 대상을 관찰하여 핵심적인 특징(속성과 행위)을 뽑아내는 과정이다.

이때 관련있는 것들을 묶게되면 캡슐화가 되고 묶은 개념은 추상화가 되고 주체는 클래스가 된다.

'객체'는 클래스로 부터 실체화 된것으로 눈에 보이며 실체한다.

'클래스'는 추상적이기에 눈에 보이지 않고 개념적으로만 존재한다.

 

2. 캡슐화

속성과 행위를 관련있는 것끼리 묶는다.

여기서 중요한 것은 접근이 필요한 부분을 제외하고 구체적인 로직은 내부로 숨긴다. (=은닉성)

구체적인 로직을 내부로 은닉하는 목적

  • 클래스 내부 구현의 '응집도'를 증가
  • 외부 다른 클래스와의 '결합도'를 감소
    • 이때 일반적인 객체지향언어는 '접근제한자'를 지원한다. (public, private, protected)

 

3. 상속

대상이 되는 클래스의 모든 특징을 물려받는 것, 이때 자식 클래스로 부터 부모 클래스가 대체되어도 의미가 성립되어야한다.

계층형 구조

  • 부모 클래스와 자식클래스는 '상속관계'
  • 관계가 아래로 내려갈수록 '구체화된다'라고 말한다. (=> 고유 특징이 증가)
  • 관계가 위로 올라올수록 '일반화된다'고 말한다. (=> 더 많은 객체에 영향을 준다)

 

장단점

장점

  • 부모 클래스로 부터 물려 받은 특징으로 인해 같은 내용을 다시 구현할 필요가 없어 '코드의 재사용성'이 향상된다.

단점

  • 재 사용성만 고려하여 상속한다면 혼란이 생긴다.
  • 상속은 '다형성'을 구현하기 위해 사용할 것을 권장한다.
    • 좋은 상속관계는 is-a 관계 (~은 ~이다) : 바나나는 과일이다 / 자동차는 바퀴가 있는 탈 것이다
    • 혼란을 줄 수 있는 상속관계는 has-a 관계 : 사람-팔 / 자동차-바퀴 / 새-날개

 

4. 다형성

하나의 속성이나 행위가 상황에 따라 다른 의미로도 해석될 수 있는 특성으로 오버로딩, 오버라이딩을 통해 다형성을 구현 할 수 있다.

  • 오버로딩
    • 매개 변수에 따라 여러 종류의 타입을 받아 같은 기능으로 하도록 하기 위한 작업
    • 자바스크립트는 자유로운 언어이므로 기본 제공하지는 않는다
    • 함수는 변수로 취급하며 모든 변수는 전역 객체로 취급하기 때문에 같은 이름이라면 하나만 취급
    • 따라서 타입체크해서 기능을 구현하도록 함수를 만들 수는 있다
  • 오버라이딩
    • 상위 클래스의 메서드를 하위 클래스에서 재 정의하는 것(상속)

 

 

절차적 프로그래밍과 객체지향 프로그래밍 차이

두 방식이 아예 반대개념이라고 할 수는 없다.

둘다 명령형 프로그램의 하위 개념이기에 공유하는 것이 많다.

그리고 절차적이지 않은 프로그램은 없기 때문이다.

다만

  • 절차적 프로그래밍
    • 프로그램의 순서와 흐름을 먼저 세우고 필요한 자료구조와 함수를 설계
    • (=데이터 중심으로 절차적 실행에 초점)
  • 객체지향 프로그래밍
    • 반대로 자료구조와 함수를 먼저 설계하고 그 후 실행순서와 흐름을 설계
    • (=객체간의 관계에 초점)

 

선언현 프로그래밍

함수형 프로그래밍 (위키백과)

순수함수를 보조함수와 조합하고 소프트웨어를 만드는 방식

로직내에 복잡성을 해결하고 변수사용을 억제하여 상태변경을 피하려는 프로그래밍 패러다임

 

특징

1. 일급객체

사용할때 다른 요소와 아무런 차별이 없는 객체 (자바스크립트 함수는 객체, 일급함수)

  1. 변수나 데이터 구조 안에 담을 수 있다
  2. 파라미터로 전달 할 수 있다
  3. 반환값(return value)로 사용할 수 있다
  4. 할당에 사용한 이름과 관계없이 고유한 구별이 가능하다
  5. 동적으로 프로퍼티 할당이 가능하다
  6. 비교연산이 가능하다

 

2. 고차함수

람다 계산법에서 만들어진 용어로 함수는 함수를 파라미터로 전달할 수 있어야하며 함수의 반환값으로 함수를 사용할 수 있습니다. (일급 객체의 부분집합)

(React의 고차컴포넌트는 컴포넌트를 이용하여 위의 조건을 만족하는 컴포넌트를 말한다)

 

3. 불변성

변하지 않는 성질을 말한다.

자바스크립트는 자유로운 언어로 데이터의 변경이 언제든 가능하나 안되는 언어들이 존재한다.

불변성을 지키기 위해서는 데이터 변경이 필요할 경우 원본을 유지한 채 복사본을 만들어 작업해야한다.

 

4. 순수함수

동일한 입력에는 항상 같은 값을 반환해야한다.

함수의 실행은 프로그램의 실행에 영향을 미치지말아야한다. (Side Effect가 없어야함)

함수 내부에서 인자값의 변경이나 프로그램의 상태를 변경하면 안된다.

 

5. 합성함수

새로운 함수를 만들거나 계산하기 위해서는 둘 이상의 함수를 조합하는 과정을 말한다.

함수형 프로그래밍은 작은 여러개의 함수들로 이루어져 있기에 이러한 함수들을 연쇄적으로 또는 병렬로 호출해서 더 큰 함수를 만드는 과정으로 전체 프로그래밍을 구축한다.

 

 

명령형 프로그래밍과 함수형 프로그래밍 비교

 

명령형 프로그래밍

함수형 프로그래밍

프로그램이란

프로그램은 명령의 수행이다

프로그램은 함수의 계산이다

중점적 시각

어떻게?

무엇?

 

 

객체지향 프로그래밍과 함수형 프로그래밍의 차이

함수형 프로그래밍과 객체지향 프로그래밍은 약간의 차이가 있다.

  • 객체지향: 관리하는 모듈함수에 의한 재사용성에 관심을 가지고 있으며 클래스(또는객체,Object)가 일급객체
    • 클래스와 객체들의 관계를 중심으로 코드 작성
    • 상태, 멤버변수, 메서드 간의 긴밀한 관계
    • 멤버변수의 상태에 따라 결과가 달라짐
  • 함수형: 순수함수와 일급객체에 관심을 가지고 있으며 함수(Function)자체가 일급객체
    • 값의 연산 및 결과 도출 중심으로 코드 작성
    • 함수 내부로 넘겨받은 인자 값을 별도로 저장하지 않으며 간결한 과정으로 처리하고 매핑하는데 주 목적입니다.

 

 

 

+ Recent posts