1. 프로미스
자바스크립트의 프로미스(Promise)는 비동기 작업의 완료 또는 실패를 처리하기 위한 객체입니다. 프로미스는 주로 시간이 걸리는 작업(예: 네트워크 요청, 파일 읽기 등)을 처리할 때 사용되며, "미래에 결과를 약속한다"는 개념으로 동작합니다. new Promise()를 통해 생성하며, 내부에는 resolve와 reject라는 두 가지 콜백이 있어 작업이 성공하면 resolve, 실패하면 reject를 호출합니다. 이후 .then()으로 성공 결과를 처리하고, .catch()로 오류를 처리할 수 있으며, .finally()로 성공 여부와 상관없이 마지막에 실행할 코드를 작성할 수 있습니다. 이를 통해 콜백 지옥(callback hell)을 피하고, 코드 흐름을 더 읽기 쉽게 만들어 줍니다.
1. 콜백 지옥
콜백 지옥(Callback Hell)은 자바스크립트에서 비동기 작업을 순차적으로 처리하기 위해 콜백 함수를 중첩해서 사용할 때 발생하는 코드 구조입니다. 여러 개의 콜백 함수가 안쪽으로 계속 중첩되면서 코드가 "피라미드처럼 오른쪽으로 들여쓰기되어" 가독성이 떨어지고, 유지보수가 어려워지는 문제가 생깁니다. 예를 들어, 서버 요청 후 그 결과로 또 다른 요청을 하고, 그 결과로 또 다른 작업을 해야 할 때 각각의 작업을 콜백 안에서 처리하면 코드가 복잡해지고 오류 처리가 어려워집니다. 이런 문제를 해결하기 위해 Promise, 그리고 이후에는 async/await 같은 문법이 도입되어 보다 깔끔하고 직관적인 비동기 코드 작성을 가능하게 해주었습니다.
2. Promise의 3가지 상태
- 대기(Pending): 아직 작업이 끝나지 않은 상태
- 이행(Fulfilled): 작업이 성공적으로 끝난 상태 → resolve()
- 거부(Rejected): 작업이 실패한 상태 → reject()
3. 문법 구조
const promise = new Promise((resolve, reject) => {
// 비동기 작업 수행
if (성공조건) {
resolve(결과값);
} else {
reject(에러값);
}
});
promise
.then(성공했을 때 실행할 코드)
.catch(실패했을 때 실행할 코드)
.finally(항상 실행할 코드);
console.log("요청을 보냅니다...");
const getData = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true; // 성공 여부 (true 또는 false)로 변경하여 확인
if (success) {
resolve("서버에서 데이터를 성공적으로 받아왔습니다!");
} else {
reject("서버 요청 실패!");
}
}, 2000); // 2초 후 실행
});
getData
.then((result) => {
console.log("성공:", result);
})
.catch((error) => {
console.log("실패:", error);
})
.finally(() => {
console.log("작업 완료");
});
function orderCoffee(menu) {
console.log(`☕ ${menu} 주문을 접수했습니다. 잠시만 기다려주세요.`);
const availableMenu = ["아메리카노", "카페라떼", "바닐라라떼"];
return new Promise((resolve, reject) => {
setTimeout(() => {
if (availableMenu.includes(menu)) {
resolve(`${menu}가 준비되었습니다! 맛있게 드세요 :)`);
} else {
reject(`죄송합니다. ${menu}는 판매하지 않습니다.`);
}
}, 2000);
});
}
// 사용
orderCoffee("아메리카노")
.then((message) => {
console.log(message);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log("주문이 완료되었습니다.");
});
function getBanana() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('🍌')
}, 1000)
})
}
function getApple() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('🍎')
}, 3000)
})
}
function getOrange(){
return Promise.reject(new Error('오렌지 없음'))
}
getBanana()
.then((banana) => getApple().then((apple) => [banana, apple]))
.then(console.log)
// Promise.all: 병렬적으로 한번에 Promise들을 실행. 하나의 프로미스라도 실패하면 전체를 에러로 처리함
Promise.all([getBanana(), getApple()])
.then((fruits) => console.log('all', fruits))
Promise.all([getBanana(), getApple(), getOrange()])
.then((fruits) => console.log('all', fruits))
.catch(console.log)
// Promise.race: 주어진 Promise중에 가장 빨리 수행된 것이 실행
Promise.race([getBanana(), getApple()])
.then((fruits) => console.log('race', fruits))
// Promise.allSettled: 여러 프로미스를 병렬적으로 처리하되 하나의 프로미스가 실패해도 무조건 이행
Promise.allSettled([getBanana(), getApple(), getOrange()])
.then((fruits) => console.log('allSettled', fruits))
.catch(console.log)
2. async / await
async는 자바스크립트에서 비동기 작업을 보다 간결하고 읽기 쉽게 만들기 위해 사용하는 키워드입니다. 함수 앞에 async를 붙이면 해당 함수는 항상 프로미스를 반환하게 되며, 이 안에서 await 키워드를 함께 사용할 수 있습니다. await는 프로미스가 처리될 때까지 기다렸다가, 결과를 받아올 수 있도록 도와줍니다. 이를 통해 비동기 작업을 마치 동기 코드처럼 자연스럽게 작성할 수 있어, 복잡한 .then(), .catch() 체인을 피하고 코드 가독성을 높일 수 있습니다.
function orderCoffee(menu) {
console.log(`☕ ${menu} 주문을 접수했습니다. 잠시만 기다려주세요.`);
const availableMenu = ["아메리카노", "카페라떼", "바닐라라떼"];
return new Promise((resolve, reject) => {
setTimeout(() => {
if (availableMenu.includes(menu)) {
resolve(`${menu}가 준비되었습니다! 맛있게 드세요 :)`);
} else {
reject(`죄송합니다. ${menu}는 판매하지 않습니다.`);
}
}, 2000);
});
}
// async/await 방식
async function startOrder() {
try {
const result = await orderCoffee("아메리카노"); // 주문
console.log(result);
} catch (error) {
console.log(error);
} finally {
console.log("주문이 완료되었습니다.");
}
}
startOrder();
'프론트엔드 > JavaScript' 카테고리의 다른 글
fetch (0) | 2025.04.18 |
---|---|
브라우저에 데이터 저장하기 (0) | 2025.04.17 |
JSON (0) | 2025.04.16 |
정규식 (0) | 2025.04.16 |
이벤트 (0) | 2025.04.16 |