[Dev-Immersion] 3주차 개념 스터디

hj·2021년 8월 18일
0

Dev-Immersion

목록 보기
4/5
post-thumbnail

TypeScript

타입스크립트는 자바스크립트에 타입을 추가한 언어이다.

TypeScript 사용 이유

타입 체크를 통한 오류 발견: 자바스크립트는 동적 타입 언어로서 런타임에 코드의 오류를 알 수 있지만 정적 타입 언어인 타입스크립트는 코드를 작성할 때 오류를 미리 발견할 수 있다.

function sum(a, b) {
	return a + b;
}

console.log(sum('0', '10')); // '010' 출력

sum 함수는 인자로 숫자 값이 들어와 두 수의 합을 계산하도록 의도했지만 문자열 값이 들어와도 에러를 발생시키지 않아 틀린 것을 알아채지 못한다.

function sum(a: number, b: number) {
	return a + b;
}

console.log(sum(0, 10)); // 10 출력

반면 타입스크립트는 함수의 인자를 타입을 지정할 수 있어 의도했던 값이 아닌 경우 에러를 발생시켜 오류를 바로잡을 수 있다.

객체 지향 프로그래밍: 클래스, 인터페이스, 상속 등 객체 지향 프로그래밍을 지원하여 크고 복잡한 프로젝트의 코드 기반을 쉽게 구성할 수 있다. (중복 코드가 줄어들고, 코드의 가독성이 높아짐.)

Javascript의 비동기 기술

동기 vs 비동기

동기는 현재 진행중인 작업이 완료될 때까지 뒤에 있는 작업들은 실행될 수 없다. 즉, 하나의 작업이 끝나야 다음 작업이 실행된다. 반면, 비동기는 앞의 작업 완료 여부와 상관없이 뒤에 있는 작업이 실행되는 것으로 동시에 여러 작업이 실행될 수 있다.

blocking vs non-blocking

blocking과 non-blocking은 제어권을 누가 가지고 있느냐의 차이이다.

blocking: function A가 function B를 호출했을 때 제어권을 function B에게 넘겨준다.

non- blocking: function A가 function B를 호출했을 때 제어권은 그대로 function A가 가지고 있다.

JS의 비동기 처리 기술 변화

비동기 처리를 하는 이유
자바스크립트는 동기적으로 실행되는 언어이다.

function hello() {
    for (let i = 0; i < 1000000000; i++) {

    }
    console.log('hello');
}

console.log('시작');
work();
console.log('끝');

위의 코드가 실행되면 시작, hello, 순서로 출력된다. hello 함수가 시간이 오래 걸리더라도 실행이 완료된 후에 다음으로 넘어간다.

DB로 데이터 요청, API 호출 등 시간이 오래 걸리는 작업을 기다리고 싶지 않다면 비동기 함수를 사용하면 된다. 그러면 코드의 흐름을 막지 않고 동시에 다른 작업도 진행할 수 있다.

const hello = () => {
    setTimeout(() => {
        console.log('hello');
    }, 1000);
}

console.log('시작');
hello();
console.log('끝');

위의 코드는 자바스크립트의 비동기 함수인 setTimeout 함수를 이용한 것이다. setTimeout 함수는 2개의 인자를 입력 받는데, 두번째 인자 값에는 기다리는 시간을, 첫번째 인자 값에는 기다린 후 실행될 작업인 콜백 함수를 입력 받는다.

코드를 실행하면 시작, , hello 순서로 출력된다.


자바스크립트에서 비동기 작업을 처리하는 방법에는 콜백함수, Promise, async-await 세가지가 있다. 이들을 이용해 비동기 작업의 순서를 제어할 수 있다.

비동기 작업: setTimeout, AJAX 요청(서버에 데이터 요청) 등

Callback function

콜백함수는 다른 함수의 인자로 넘기는 함수를 말한다. 특정 함수가 실행된 후, 실행될 함수이다.

비동기 작업을 처리할 때 생기는 문제점을 해결할 수 있는 방법
비동기 작업은 순차적인 처리가 보장되지 않기 때문에 비동기 작업이 완료된 후, 실행되어야 할 작업은 콜백 함수로 넘겨 순서를 제어해야 한다.

하지만 비동기 작업의 순서를 제어하기 위해 콜백 함수를 사용한다면, 여러 개의 콜백 함수를 사용할 경우 콜백 함수가 중첩되어 코드의 가독성이 떨어지게 된다. 이 문제를 해결하기 위해 Promise를 쓰기 시작했다.

Promise

ES6부터 추가된 자바스크립트의 표준 내장 객체이다. 이 객체에는 비동기 작업의 결과 값이 담긴다. Promise는 then, catch라는 함수를 이용해서 비동기 작업의 순서를 제어할 수 있다.

생성자를 통해서 Promise 객체를 만들 수 있다.

new Promise();

생성자의 인자로 executor 함수가 들어오는데, executor 함수는 인자로 resolve, reject 함수를 가진다. 생성자로 객체를 만드는 순간 pending(대기) 상태가 된다.

// executor
(resolve, reject) => { /* ... */ }

// pending 상태
new Promise((resolve, reject) => { /* ... */ }); 

executor 함수의 resolve 함수를 실행하면 fulfilled(이행) 상태가 되고, reject 함수를 실행하게 되면 rejected(거부) 상태가 된다.

코드의 로직이 성공된 경우에는 resolve 함수를, 실패한 경우에는 reject 함수를 호출한다.

// fulfilled
new Promise((resolve, reject) => resolve());
// rejected
new Promise((resolve, reject) => reject());

Promise 객체의 resolve 함수가 호출되어 fulfilled 상태가 되면 then 안에 있는 콜백 함수가 실행된다. 이때, resolve 함수의 인자로 문자열이나 객체를 넣어주면 then의 콜백 함수의 인자로 전달할 수 있다.

function p() {
    /**
     * 함수가 호출될 때 Promise 객체가 만들어져서
     * pending 상태가 되도록 한다.
     */
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('hello'); 
        }, 1000);
    });
}

p().then(() => {
    console.log('1000ms 후에 fulfilled');
})

Promise 객체의 reject 함수가 호출되어 rejected 상태가 되면 catch 안에 있는 콜백 함수가 실행된다. resolve 함수와 마찬가지로 reject 함수에 값을 넣어주면 catch 함수의 콜백 함수의 인자로 값을 전달할 수 있다.

그리고, fulfilled나 rejected된 후에 실행해야할 작업이 있다면 finally 함수의 인자로 콜백 함수를 넣어주면 된다.

function p() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error('error 발생'));
        }, 1000);
    });
}

p()
    .then(() => {
        console.log('1초 후에 fulfilled');
    })
    .catch((error) => {
        console.log('1초 후에 rejected', error);
    })
    .finally(() => {
        console.log('작업 끝!!!!');
    });

then 함수에 다시 새로운 Promise 객체를 만들어서 반환하여 비동기 작업을 순차적으로 처리할 수 있다. Promise를 사용하면 콜백 함수를 이용해서 비동기 작업을 처리한 코드보다 가독성이 좋아지게 된다.

p()
  .then(() => p()) 
  .then(() => p())
  .then(() => p())
  .then(() => console.log('4초 후에 fullfiled'));

async-await

Promise를 기반으로 하고 있으며, Promise를 쉽게 사용할 수 있도록 도와준다.

우선 함수에 async 키워드를 붙이게 되면 그 함수는 비동기 함수가 된다.

async function 함수이름() { }
const 함수이름 = async () => { }

await은 async 함수 안에서만 사용될 수 있는 키워드로 Promise의 then 함수와 비슷한 역할을 한다. await은 키워드 뒤에 오는 Promise가 결과 값을 가질 때까지 비동기 함수의 실행을 멈추게 만든다. 이렇게 해서 비동기 작업의 순서를 제어할 수 있게 된다.

그리고 try catch문을 이용해서 Promise가 rejected가 된 경우 catch문을 통해 에러를 처리할 수 있도록 해준다. fulfilled된 경우에는 try 문 안에 있는 로직이 계속 실행된다.

function p(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(ms);
        }, ms);
    });
}

// Promise 객체를 이용해서 비동기 로직 수행
p(1000).then(ms => {
     console.log(`${ms}ms 후에 실행`);
 });

// Promise 객체를 리턴하는 함수를 await로 호출
(async () => {
    try {
        const ms = await p(1000);
        console.log(`${ms}ms 후에 실행`);
    } catch (e) {
        console.log(e);
    }
})();

CORS

CORS(Cross-Origin Resource Sharing)란 추가적인 HTTP 헤더를 사용해서 웹 애플리케이션이 다른 origin의 리소스에 접근할 수 있도록 하는 메커니즘이다. 웹 애플리케이션은 리소스가 자신의 origin과 다를 때 교차 출처 HTTP 요청을 실행한다.

웹 애플리케이션은 SOP(Same Origin Policy) 정책을 따른다. SOP는 같은 출처에서만 리소스를 공유할 수 있는 정책이다. 만약, 다른 출처의 리소스를 사용하려면 CORS 정책을 지켜야 한다. CORS 정책을 지키지 않는다면 다른 출처로 리소스 요청을 할 수 없다.

Origin이란? 프로토콜+호스트 명+포트 번호(https://www.practice.com:80)를 의미한다. 포트 번호는 생략이 가능하다.

같은 Origin인 경우는? Protocol, Host, Port가 모두 일치하면 같은 Origin이라고 본다.

http://www.practice.com:80
https://www.practice.com:80
-> 프로토콜의 종류가 다르므로 같은 Origin이 아니다.

CORS 정책 위반시 에러 해결 방법

  • Access-Control-Allow-Origin
    서버의 응답 헤더에 Access-Control-Allow-Origin 값으로 원하는 Origin 값을 넣어주는 것이다. 이 응답 헤더에 추가된 Origin이라면 서버와 브라우저가 다른 Origin이라도 리소스를 공유할 수 있게 된다.

  • 웹팩 개발 서버의 Proxy 사용
    proxy를 사용하게 되면 웹 애플리케이션은 현재 개발하고 있는 서버의 주소로 리소스를 요청하게 된다. 요청을 받은 proxy는 실제 서버로 요청을 해서 응답을 웹 애플리케이션으로 반환시켜준다. 웹 애플리케이션은 같은 origin으로 요청을 보냈다고 생각하기 때문에 에러를 발생시키지 않는다.
    개발 환경인 경우에만 사용 가능하다. 실제로 웹 애플리케이션을 배포했을 때는 서버측에서 Access-Control-Allow-Origin 응답 헤더를 추가해주는게 맞다.

CORS 정책을 위반했을 때 나타나는 에러는 웹 애플리케이션 측에서 내는 것이기 때문에 서버 간 통신을 할 때는 CORS 정책이 적용되지 않는다.

JWT

JWT(Json Web Token)는 클라이언트와 서버, 서비스와 서비스 사이 통신을 할 때 권한 인가를 위해 사용하는 암호화된 토큰이다. 웹서버는 JWT를 HTTP의 헤더나 URL의 파라미터를 이용해 전달할 수 있다.

JWT는 문자열로 구성되어 있는데 header, payload, signature 3가지가 .을 통해서 구분되어있다. JWT가 디코딩되면 JSON 객체 형태가 된다.

테스트 프레임워크

Jest

페이스북에서 만든 자바스크립트 테스트 프레임워크이다. Babel, TypeScript, Node.js, React, Angular, Vue 등에서 사용할 수 있다.

Jest 사용 방법

  1. npm 설치
    npm install jest
  2. package.json 파일에 script 값을 jest로 바꿔준다. 이렇게 설정해주면 npm run test를 통해 jest를 사용할 수 있다.
  3. test.js로 끝나거나 __test__ 디렉토리 안에 있는 파일들은 테스트 파일로 인식한다.

테스트 코드는 보통 아래와 같은 형식으로 작성된다. toXxx는 Matcher라고 하는데 Jest는 Matcher를 이용하여 값을 테스트한다.

test("테스트 설명", () => {
  expect("검증 대상").toXxx("기대 결과");
});

Jest 이외에는 Mocha, Jasmine 등이 있다.

[FE]

React의 Virtual Dom

리액트는 렌더링을 할 때마다 가상돔(Virtual Dom)을 만들고 이전의 가상돔과 비교를 하여 바뀐 부분이 있는 경우에만 실제 돔을 수정한다. 가상돔을 사용함으로써 리액트는 렌더링 성능을 높였다.

Class Component vs Functional Component

리액트에서 컴포넌트를 선언하는 방법에는 2가지가 있는데 클래스 또는 함수로 선언하는 방법이다. 현재 함수형 컴포넌트가 더 많이 사용되고있다.

클래스형 컴포넌트는 state와 Lifecycle 메소드가 있기 때문에 개발할 수 있는 기능이 많다. 하지만 react hook이 나오면서 함수형 컴포넌트에서도 상태값을 변경하거나 useEffect를 이용해서 다양한 기능들을 구현할 수 있게 되었다.

  • 클래스형 컴포넌트
import React,  { Component } from 'react';

class Example extends Component {
	render () {
    	// jsx를 반환
    }
}

export default Example;
  • 함수형 컴포넌트
import React from 'react';

function Example() {
	return () {
    	// jsx를 반환
    }
}

export default Example;

React Hook

react hook은 함수형 컴포넌트에서도 상태를 가지거나 리액트의 기능들을 사용할 수 있도록 만들어주는 함수이다.

useState

  • 함수형 컴포넌트에서도 상태를 관리할 수 있게 해주는 리액트 훅
  • 클래스형 컴포넌트의 this.state와 똑같은 기능을 가진다.
import React, { useState } from 'react'; 

const [state, setState] = useState(defaultValue);

import 구문을 통해서 useState 훅을 불러오면 사용할 수 있다. useState 함수 안에는 상태가 가질 초기 값을 세팅해주어야 한다. 배열 구조분해를 이용해 useState 함수의 반환값을 받는데, 첫번째 변수는 state 변수, 두번째 변수는 상태값 변경함수이다.

useEffect

컴포넌트가 마운트 or 언마운트 or 업데이트 될 때 특정 작업(api 호출 등)을 처리하는 하는 곳이다.

import React, { useEffect } from 'react';

function Example() {
	useEffect(() => {
    	// api 요청 등을 할 수 있다.
    }, []);
}

export default Example;

React Router

리액트에서 SPA(Single Page Application)를 만들기위해 사용되는 라이브러리이다.

SPA란 하나의 페이지로 구성된 웹 애플리케이션을 말한다. 처음 웹 애플리케이션에 필요한 정적 리소스를 서버로부터 받아오고, 그 이후에 일어나는 라우팅(주소에 따라 다른 UI를 보여주는 것)은 클라이언트 쪽에서 담당한다. 그리고 페이지를 전환했을 때 새로운 데이터가 필요한 경우에 서버로 데이터를 요청한다.

원래 전통적인 웹 애플리케이션은 페이지가 바뀔 때마다 서버로 페이지를 요청했음.

SPA는 링크를 클릭할 때마다 다른 페이지로 이동하는 것이 아니라 자바스크립트를 사용해서 HTML 요소들을 동적으로 바꿔준다. 그래서 한 페이지로 구성된 앱인 것이다.

Redux

리덕스란? 앱의 상태 업데이트 및 관리, 액션이라는 이벤트 사용하기 위한 라이브러리이다.

사용하는 이유는?

  • 리덕스는 어플리케이션의 많은 부분에 필요한 상태인 "global" 상태를 관리할 수 있도록 해준다.
  • 상태가 언제, 어디서, 왜, 어떻게 업데이트 되는지, 이러한 변경이 일어났을 때 어플리케이션 로직이 어떻게 작동하는지 쉽게 이해할 수 있다.

언제 사용?

  • 어플리케이션의 여러 부분에서 상태가 사용될 때.
  • 자주 상태가 업데이트 될 때

reference

0개의 댓글