Q. Promise의 기능과 필요한 이유에 대해서 설명해주세요
promise는 자바스크립트 비동기 처리에 사용되는 객체다.
비동기 처리란, 앞서 로직의 실행의 결과를 기다리지 않고, 나머지 코드를 먼저 실행하는 방법이다.
보통 서버에서 데이터를 받아올 때 사용하는데 서버에 데이터를 요청했을때 응답이 언제 올지 모르기 때문이다.
비동기 작업을 처리하는 방법에는 callback
함수와 setTimeout
로 처리를 하는 방법이 있다.
// callback을 사용하지 않았을 경우
function first() {
console.log("1번째");
}
function second() {
setTimeout(() => {
console.log("2번째");
}, 1000);
}
function third() {
console.log("3번째");
}
first();
second();
third();
// 1번째 3번째 2번째
// 2. callback을 사용할 경우
function first(cb) {
setTimeout(() => {
console.log("1번째");
cb();
});
}
function second(cb) {
setTimeout(() => {
console.log("2번째");
cb();
}, 1000);
}
function third(cb) {
setTimeout(() => {
console.log("3번째");
cb();
});
}
first(() => {
second(() => {
third(() => {
console.log("fin");
});
});
});
// 1번째 2번째 3번째 fin
// 그러나 함수 실행 단에서 callback 지옥 발생 !!
위 코드를 보면 비동기 처리라도 순차적으로 처리해야 할 상황이 온다.
ex) 데이터를 받아와서 해당 데이터로 작업을 해줘야 할 경우
이때 callback 함수를 사용한다. 하지만, 너무 많은 callback함수를 사용할 경우 마지막처럼 가독성이 떨어지는 코드가 나오게 된다.
위 문제를 해결하기 위해 Promise
객체를 이용한다.
Promise
의 간단한 구조는 다음과 같다.
Promise((resolve,reject)=>{
if(success){
resolve(response)
}
else{
reject(error)
}
}
Promise 내 함수가 정상적으로 작동하면 응답과 함께 resolve 해주고
실패 시 reject에 돌입한다.
function taskA(a, b, cb) {
setTimeout(() => {
const res = a + b;
cb(res);
}, 2000);
}
function taskB(a, cb) {
setTimeout(() => {
const res = a * 2;
cb(res);
}, 1000);
}
function taskC(a, cb) {
setTimeout(() => {
const res = a * -1;
cb(res);
}, 3000);
}
taskA(1, 2, (res_a) => {
taskB(res_a, (res_b) => {
taskC(res_b, (res_c) => {
console.log("taskC Result : ", res_c);
});
});
});
다음과 같은 코드를 promise로 작성하면 아래와 같다.
function taskA(a, b) {
return new Promise((resolve, reject) => {
if (a && b != undefined) {
setTimeout(() => {
const res = a + b;
resolve(res);
}, 2000);
} else {
reject("error!!!!!!");
}
});
}
function taskB(a) {
return new Promise((resolve, reject) => {
if (a != undefined) {
setTimeout(() => {
const res = a + 2;
resolve(res);
}, 2000);
} else {
reject("error");
}
});
}
function taskC(a) {
return new Promise((resolve, reject) => {
if (a != undefined) {
setTimeout(() => {
const res = a + 3;
resolve(res);
}, 2000);
} else {
reject("error");
}
});
}
// 정상적인 인자를 전달했을때
taskA(1,2)
.then((resA) => {
return taskB(resA);
})
.then((resB) => {
return taskC(resB);
})
.then((resC) => {
console.log(resC); // 8 (정상적으로 잘 나옴)
});
// 인자를 하나 빼먹었을 때
taskA(1)
.then((resA) => {
return taskB(resA);
})
.then((resB) => {
return taskC(resB);
})
.then((resC) => {
console.log(resC);
});
위와 같이 오류가 생기면 reject에 돌입하게 된다.
Answer
promise는 비동기 처리를 위해 필요한 자바스크립트 객체로, 성공 시 resolve를 통한 응답을, 실패 시 reject를 통한 에러를 보내줍니다. 비동기 처리 방식에서 데이터를 받아와서 사용할 때 이용하는 콜백 함수의 콜백 지옥을 개선하기 위해 Promise 객체를 사용합니다.
Q. 순수함수란 무엇인가요 ? 불변성과 사이트 이펙트와 연결하여 설명해주세요.
순수함수란 동일한 인자가 전달되면 항상 동일한 결과가 전달되는 함수다.
function plusnum1(a,b){
return a+b;
}
plusnum(1,2); // 3
plusnum(1,2); // 4
위 함수 plusnum1은 어떠한 상황이라도 동일인자가 전달되면 동일한 결과값이 전달된다.
let other = 10;
function plusnum2(a,b){
return a+b+other;
}
plusnum(1,2);
other = 20;
plusnum(1,2);
반면 위 plusnum2는 외부 인자가 개입을 한다.
외부 인자의 값에 따라 함수의 결과값도 변하게 된다.
plusnum1은 순수함수고 plusnum2는 순수함수가 아니게 된다.
plusnum1은 어떠한 경우에도 같은 값을 리턴시키므로 불변성을 지키는 함수라고 볼 수 있다.
반면 plusnum2는 외부 요인(sideEffect)에 따라 값이 변화된다.
A
순수함수란, 불변성을 지키며 사이드이펙트의 영향을 받지 않는 함수입니다. 불변성을 지킨다는 것은, 값을 직접 변경하지 않고 객체 복사와 같은 방법을 통해 값을 변경시키는 것입니다. 만약 사이드이펙트인 외부 API가 불변성을 지키지 않고 직접적으로 값을 변경하면 후에 다른 데이터가 들어오면 오류를 발생시킬 수 있습니다.
Q. React의 state와 props에 대해서 설명 해주세요.
props 프로퍼티란 상위 컴포넌트가 하위 컴포넌트에 값을 전달해줄 때 사용하는 인자다.
// parent.js
function Parent() {
const userinfo = {
name:"jasub",
age:26,
text:"hello"
}
return (
<div>
<Child name={userinfo.name} age={userinfo.age} text={userinfo.text} />
</div>
);
}
// Child.js
function Child(props) {
return (
<div>
<div>{props.name}</div>
<div>{props.age}</div>
<div>{props.text}</div>
</div>
);
}
프로퍼티란 자식 컴포넌트 입장에선 읽기 전용이므로 수정할 수 없다.
state는 props와는 다르게, 선언된 컴포넌트 내에서 관리된다.
state는 선언부에서 관리되며 state값을 props처럼 하위 컴포넌트에 넘겨줄 수 있지만, 해당 컴포넌트는 state를 사용(참조)하는 것뿐이지 관리를 하지 못한다.
따라서, state를 사용하는 하위 컴포넌트에선 사용자에게 state를 직접적으로 노출하지 않는다. (캡슐화)
https://velog.io/@liso_o/React-Props-State
state와 props에 대해 내가 작성한 글
A.
state는 데이터를 가지고 있는 객체로써 선언된 컴포넌트에서 관리합니다.
props는 부모 컴포넌트가 자식 컴포넌트에게 데이터나 값을 전달 해줄때 사용합니다.
state에 있는 데이터를 props를 통해 자식 컴포넌트에 전달할 수 있지만, 자식 컴포넌트는 state를 오직 참조만 할 뿐 수정하지도 못하고 자식 컴포넌트 사용자에게 state가 노출되지도 않습니다.
사용자가 알 필요가 없는 데이터를 은닉하는 캡슐화를 하여 코드를 작성하는 것이 state와 props를 잘 사용하는 방법입니다.
Q. React 컴포넌트의 key 속성에 대해서 설명해주세요
리액트에서 key는 컴포넌트 배열을 렌더링 했을때 어떤 항목을 변경,추가 또는 삭제할지 식별하는 것을 도와준다.
key는 각각 컴포넌트에 안정적인 고유성
을 부여하기 위해 컴포넌트 엘리먼트 내부에 지정해야 한다.
보통은 엘리먼트 내 고유 ID를 key로 사용하지만, 만약 없다면 최후의 수단으로 컴포넌트 배열의 인덱스
를 사용한다.
<ul>
<li>first</li>
<li>second</li>
</ul>
==>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
위 코드와 같이 단순하게 바로 밑에 list를 추가하는 경우는 큰 상관이 없지만,
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
==>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
위처럼 리스트 맨 앞에 컴포넌트를 추가하는 경우는 성능이 좋지 않다.
위와 같이 맨 앞에 추가하는 경우 React는 모든 자식 컴포넌트를 변경한다. 매우 비효율적이라는것.
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
=>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
따라서 위와 같이 key를 추가해주면, 기존에 있던 컴포넌트는 변경 없이 이동만 하면 된다.
A.
React에서 key는 컴포넌트에게 안정적인 고유성을 부여해주는 값으로 보통은 데이터 내의 값중 key에 적절한 값을 key로 지정하지만 없는 경우 엘리먼트 배열의 인덱스로 대체합니다.
key를 지정하지 않았을 경우 새로운 컴포넌트가 추가될 때 기존 컴포넌트를 전부 변경하는 매우 비효율적인 작업이 이루어질 수 있습니다.
Q. useEffect의 dependency array에 대해서 설명해주세요.
useEffect는 컴포넌트가 렌더링 될 때 특정 작업을 실행할 수 있도록 하는 Hook 이다.
useEffecct(function,[deps])
다만, 여기서 dep에 따라 useEffect 내의 함수의 실행 유무가 결정된다.
deps 내의 값이 변경 될 때마다 useEffect가 실행이된다.
A.
useEffect의 dependency array는 useEffect가 실행되는 조건을 담당하며, 해당 배열 내 값이 변경되었을 경우 useEffect를 실행시킵니다.
예시로, 검색창에 검색어 작성 시 추천검색어가 뜨는 로직에 사용자가 작성한 검색어를 deps로 주는 방식이 있습니다.
Q. CSR과 SSR의 차이점에 대해 설명해주세요
CSR과 SSR에 대해 내가 작성한 글
https://velog.io/@liso_o/React-CSR-vs-SSR
A.
CSR과 SSR은 렌더링의 방식으로 차이점이 있다면 렌더링의 방식이 있습니다.
클라이언트 기반 렌더링의 CSR은 모든 작업을 클라이언트에서 처리하는 방식으로, 서버에서는 데이터만 받아오고 클라이언트에서 렌더링 작업을 하는 것입니다.
CSR의 장단점으로는 서버에서는 데이터만 받아오므로 빠른 페이지 이동이 가능합니다. 하지만 그만큼 사용자가 초기에 페이지를 열 때 시간이 많이 걸리고, 서버에서 저장된 html은 빈 페이지므로 좋지 않은 검색 접근성을 가지고 있습니다.
SSR은 사용자가 웹 사이트에 접속하면 서버에 저장되있는 모든 데이터와 정보를 토대로 html파일을 만들어주고 사용자가 사용할 수 있는 스크립트와 함께 클라이언트 단으로 보내줍니다.
초기 페이지 렌더링이 빠르고 검색 엔진 접근성이 뛰어나지만, 사용자가 요구하는 데이터가 많을수록 서버에서 그만큼 데이터를 가져와야 하므로 과부하가 걸리기 쉬운 단점이 있습니다.
Q. GET 메서드와 POST 메서드의 차이점에 대해 설명해주세요
http 메서드는 요청에 대해 서버에게 요청하는 작업이다.
URL에 변수(데이터)를 포함시켜 요청한다.
데이터를 Header(헤더)에 포함하여 전송한다.
URL에 데이터가 노출되어 보안에 취약하다.
전송하는 길이에 제한이 있다. 전송 길이가 너무 긴 경우 초과 데이터는 절단.
캐싱(Caching, 한번 접근 후 또 요청할 시에 빠르게 접근하기위해 레지스터에 데이터를 저장시켜 놓는 것)할 수 있다.
GET 방식은 특별히 전송하는 데이터가 없으므로 request의 body가 빈 상태로 전송된다.
URL에 변수(데이터)를 노출하지않고 요청한다.
데이터를 Body에 포함시킨다.
URL에 데이터가 노출되지않아서 기본 보안이 되어있다.
전송하는 길이에 제한이 없다.
캐싱할 수 없다.
POST 는 GET과 다르게 url이 아닌 request의 body에 데이터를 넣어서 전송한다.
따라서 Body의 데이터를 설명하는 Content-Type이 필수로 들어가야 한다.
A.
GET과 POST는 http 메서드로 서버에게 요청을 하는 메서드입니다.
두 메서드는 각각 사용처에 따라 쓰임이 결정되는데
우선, GET 메서드는 어떠한 정보를 가져와 조회하기 위해서 사용하는 방식으로 데이터를 URL에 포함시켜서 요청을 합니다. URL에 데이터가 노출된 만큼 보안에 굉장히 취약하고 캐싱이 가능합니다.
반면 POST 메소드는 데이터를 서버로 제출하여 추가 또는 수정을 할 때 사용하는 방식으로 요청의 body에 데이터를 넣어서 요청합니다. URL에 노출되지 않으므로 어느정도 기본 보안이 되어있으며
캐싱이 불가능합니다.
Q. HTTP 메시지 구조에 대해 설명해주세요
HTTP는 기본적으로 request(요청)
과 response(응답)
구조로 나뉘어진다.
request 구조는 3가지 부분으로 나뉘어진다.
GET /target.html HTTP/1.1
HTTP method는 요청의 의도를 담고 있는 GET, POST, PUT, DELETE 등이 있다.
Request Target은 HTTP Request가 전송되는 목표 주소다.
Request에 대한 추가적인 정보가 담겨있는 곳.
HTTP request가 전송하는 데이터를 담고 있는 부분으로, 전송하는 데이터가 없으면 body부분은 비어있다.
보통 POST 요청일 경우 Body에 데이터가 있다.
POST /test HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 83
Content-Type: application/json
Host: google.com
User-Agent: HTTPie/0.9.3
{
"test_id": "tmp_1234567",
"order_id": "8237352"
}
response 구조는 마찬가지로 3가지 부분으로 나뉘어진다.
HTTP Response의 상태를 간략하게 나타내주는 부분
HTTP Response의 status line또한 3가지 부분으로 구성
HTTP/1.1 200 OK
[HTTP version] [Status Code] [Status Text]
Response의 headers와 동일하다.
다만 response에서만 사용되는 header 값들이 있다.
예를 들어, User-Agent 대신에 Server 헤더가 사용된다.
Response의 body와 일반적으로 동일하다.
Request와 마찬가지로 모든 response가 body가 있지는 않다.
데이터를 전송할 필요가 없을경우 body가 비어있게 된다.