언제나 헷갈리는 Promise
JavaScript의 Promise와 동기/비동기 개념
JavaScript의 Promise는 비동기 작업을 더 효율적이고 가독성 있게 처리하기 위한 객체다. 이를 이해하려면 먼저 동기(Synchronous)와 비동기(Asynchronous)의 개념을 알아야 한다.
동기(Synchronous)와 비동기(Asynchronous)의 이해
1. 동기(Synchronous)
동기 프로그래밍은 작업이 순차적으로 실행되는 방식이다. 하나의 작업이 끝나야 다음 작업이 실행된다. 이 방식은 단순하지만, 시간이 오래 걸리는 작업이 있다면 그동안 프로그램이 멈추게 된다.
예시:
console.log('첫 번째 작업 시작');
console.log('두 번째 작업 실행');
console.log('세 번째 작업 실행');
출력 결과:
첫 번째 작업 시작
두 번째 작업 실행
세 번째 작업 실행
위 코드는 순차적으로 실행되므로 예상대로 출력된다.
2. 비동기(Asynchronous)
비동기 프로그래밍은 작업이 병렬적으로 실행될 수 있는 방식이다. 시간이 오래 걸리는 작업이 실행되는 동안에도 다른 작업을 계속 수행할 수 있다. JavaScript는 비동기 작업을 처리하기 위해 콜백(callback), Promise, 그리고 async/await를 사용한다.
예시:
console.log('첫 번째 작업 시작');
setTimeout(() => {
console.log('두 번째 작업 실행 (2초 후)');
}, 2000);
console.log('세 번째 작업 실행');
출력 결과:
첫 번째 작업 시작
세 번째 작업 실행
두 번째 작업 실행 (2초 후)
비동기 작업인 setTimeout은 타이머가 끝날 때까지 기다리지 않고 다음 작업으로 넘어간다.
Promise란 무엇인가?
Promise는 비동기 작업의 결과를 나타내는 객체이다. 현재 작업이 완료되었는지, 진행 중인지, 실패했는지를 나타내는 상태를 가진다. 비동기 작업의 성공/실패에 따라 다른 동작을 수행하도록 설계되었다.
Promise의 상태
- Pending (대기): 작업이 아직 완료되지 않은 상태.
- Fulfilled (이행): 작업이 성공적으로 완료된 상태.
- Rejected (거부): 작업이 실패한 상태.
Promise의 기본 사용법
Promise는 new Promise로 생성하며, 콜백 함수의 두 가지 매개변수 resolve와 reject를 사용한다.
예시:
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('작업이 성공했습니다!');
} else {
reject('작업이 실패했습니다.');
}
});
myPromise
.then(result => {
console.log(result); // 작업이 성공했을 경우 실행
})
.catch(error => {
console.error(error); // 작업이 실패했을 경우 실행
});
출력 결과:
작업이 성공했습니다!
Promise의 실용 예제
1. API 호출
서버에서 데이터를 가져오는 작업은 시간이 걸리기 때문에 비동기 작업으로 처리한다. Promise를 사용하면 이런 작업을 더 효율적으로 관리할 수 있다.
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('데이터를 성공적으로 가져왔습니다.');
} else {
reject('데이터 가져오기에 실패했습니다.');
}
}, 1000);
});
}
fetchData()
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
출력 결과 (1초 후):
데이터를 성공적으로 가져왔습니다.
2. Promise.all로 여러 작업 병렬 처리
여러 비동기 작업을 동시에 실행하고, 모든 작업이 완료되었을 때 실행하도록 할 수 있다.
const promise1 = Promise.resolve('작업 1 완료');
const promise2 = new Promise(resolve => setTimeout(() => resolve('작업 2 완료'), 2000));
const promise3 = new Promise(resolve => setTimeout(() => resolve('작업 3 완료'), 1000));
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // ['작업 1 완료', '작업 2 완료', '작업 3 완료']
});
async/await와 Promise
async/await는 Promise를 더 직관적이고 간단하게 사용할 수 있도록 해주는 문법이다. 비동기 작업을 마치 동기 작업처럼 작성할 수 있다.
예시:
async function fetchData() {
try {
const result = await new Promise((resolve, reject) => {
setTimeout(() => resolve('데이터를 성공적으로 가져왔습니다.'), 1000);
});
console.log(result);
} catch (error) {
console.error(error);
}
}
fetchData();
출력 결과 (1초 후):
데이터를 성공적으로 가져왔습니다.
결론
Promise는 JavaScript에서 비동기 작업을 더 효율적으로 관리하기 위해 만들어졌다. 이를 통해 복잡한 콜백 지옥을 피하고, 코드를 더 직관적이고 읽기 쉽게 작성할 수 있다. 또한, async/await를 사용하면 비동기 작업을 동기식 코드처럼 작성할 수 있어 가독성이 더욱 향상된다. 동기와 비동기의 개념을 이해하고 Promise를 적절히 활용하면 JavaScript에서의 비동기 프로그래밍을 더욱 쉽게 다룰 수 있다.