들어가기전에
자바스크립트는 동기적(Synchrous)으로 코드를 실행한다. 동기적으로 처리가 된다는 것은 우리가 작성한 순서대로 처리가 되는 것이기 때문에 어떠한 작업이 끝나야 다음 작업을 진행할 수 있으므로 어떤 작업에 대해 특정 시간을 정해놓은 후 실행을 시키고 싶다면 비동기적으로 처리를 해야한다.
비동기(Asynchronous)처리를 할 때 대표적인 함수는 setTimeout()인데, 두 개의 인자를 받고 있다. 하나는 TimeHandler라는 콜백 함수와 시간을 지정해주는 timeout을 받는다. 그래서 setTimeout()은 지정한 시간이 지난 후 콜백함수를 실행시킨다.
콜백함수는 'Call Back' 준비되면 '나중에 불러줘'와 같은 의미다.
하지만 콜백함수는 비동기 처리할 때만 사용하는 것은 아니고 synchronous callback과 asynchronous callback으로 구분되어 진다.
그렇다면 콜백지옥이란 무엇일까
콜백 안에서 다시 콜백을 부르고, 다시 콜백 안에서 다시 콜백을 네스팅하는 것을 콜백 지옥이라고 한다. 이러한 코드 구조는 가독성이 떨어지고 로직을 수정, 변경하기 어렵기 때문에 이러한 콜백 지옥을 해결하기 위해
- Promise
- async/await
으로 해결할 수 있다.
JavaScript 엔진이 Promises를 처리하는 방법
자바스크립트에서 프로미스는 비동기적인 작업을 처리하기 위한 특별한 객체다. Promise가 왜 필요한지 알려면 서버에서 받아온 데이터를 프론트엔드에서 화면에 표시해줄 때의 예시를 들 수 있다. 기본적으로 아래와 같은 API를 사용하게 된다.
$.get('url products/1', function(response) {
});
이 코드가 실행되면서 서버에 데이터 요청을 보낸다. 이때 여기서 데이터를 받아오기 전 화면에 데이터를 표시하려고 하면 오류가 발생하거나 빈 화면이 뜨기 때문에 이와 같은 문제점을 해결 하기 위해 프로미스 객체가 필요하다.
프로미스 실행
먼저 Promise 컨스트럭터를 사용하여 프로미스를 생성할 수 있는데, 이때 실행자 함수를 넘겨주어야 한다. 실행자 함수에서는 프로미스가 성공적으로 실행되었을 때(resolve)와 에러를 던졌을 때(reject) 무엇을 반환할 지를 정의해준다.
아래 자바스크립트의 프로미스 예제를 살펴보자.
const promise = new Promise((resolve, reject) =>
resolve('I am a resolved promise');
);
프로미스가 실행된 이후에 결과값을 .then() 메소드, 에러는 .catch() 메소드로 처리할 수 있다.
promise.then(result => console.log(result))
프로미스의 3가지 상태(states)
프로미스를 사용할 때 알아야 하는 가장 기본적인 개념은 프로미스의 상태다. 여기서 말하는 상태는 new Promise()로 프로미스를 생성하고 종료될 때까지 프로미스의 3가치 처리 과정을 말한다.
- Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
- Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환한 상태
- Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태
Pending(대기)
아래와 같이 new Promise() 메소드를 호출하면 대기상태가 됩니다.
new Promise();
이때 콜백 함수를 선언해 인자로 resolve와 reject를 넣을 수 있습니다.
new Promise(function(resolve, reject) {
});
Fulfilled(이행)
콜백 함수의 인자 resolve를 실행하면 이행상태로 전환할 수 있습니다. 그리고 이행 상태에는 아래와 같이 .then()을 이용하여 결과값을 받을 수 있습니다.
function getData() {
return new Promise(function(resolve, reject) {
let data = 100;
resolve(data);
});
}
/* resolve()의 결과값 data를 resolvedData로 받음 */
getData().then(function(resolvedData) {
console.log(resolvedData);
});
Rejected(실패)
콜백 함수의 인자 reject를 실행하면 실패(Rejected) 상태가 됩니다. 그리고 실패 상태과 되면 실패 처리의 결과 값을 .catch()로 받을 수 있습니다.
function getData() {
return new Promise(function(resolve, reject) {
reject(new Error("Request Failed"));
});
}
/* reject()의 결과값 Error를 err에 받음 */
getData().then().catch(function(err) {
console.log(err);
});
실제 코드에서 적용해본 결과
몇 달전 초보 개발자들이 하기 쉬운 실수였던 콜백 지옥에 빠져 🐶고생을 했는데, 바로 교통정보 API를 이용하던 중 여러 건의 API를 한꺼번에 호출하려던 중 코드가 꼬여 11초만에 하루 무료 이용 갯수가 넘어버려 계정이 정지되어 버린 일이 있어서 해당 회사에 전화해서 사정해 계정을 푼 일이 있었다. 그때 async/await과 Promise로 값이 넘어온 이후에 각 해당하는 로직을 타도록 수정을 했고 결과적으로 아래와 같은 코드를 쓰게 되었다.
function makeRequest(method, url) {
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
async function searchPubTransPath() {
let request = await makeRequest("GET", url);
}
searchPubTransPath();
참고 블로그
https://joshua1988.github.io/web-development/javascript/promise-for-beginners/
https://www.freecodecamp.org/news/synchronous-vs-asynchronous-in-javascript/
'Front End' 카테고리의 다른 글
자주 나오는 프론트엔드 개발자 취업 면접 질문 및 답변 정리-2 (0) | 2022.06.24 |
---|---|
자주 나오는 프론트엔드 개발자 취업 면접 질문 및 답변 정리-1 (0) | 2022.06.22 |
[JavaScript] ES6(ECMA Script 6) - 기본 매개변수(Default parameter) (0) | 2022.04.05 |
[HTML] <br> 태그의 줄바꿈 (0) | 2022.04.01 |
인터랙티브 웹 개발 제대로 시작하기-타이밍 제어하기 (0) | 2022.02.20 |