자바스크립트 비동기 처리와 Promise 이해
최근 자바스크립트의 비동기 처리 방식에 대한 이해는 웹 개발에 필수적입니다. 비동기 프로그래밍은 효율적인 리소스 사용과 사용자 경험을 극대화할 수 있도록 돕기 때문에 많은 개발자들이 이 주제에 대한 깊은 이해가 필요합니다. 이번 글에서는 자바스크립트의 비동기 처리 방식 중 콜백 함수와 프로미스를 비교하여 설명하겠습니다.

비동기 처리란?
비동기 처리는 자바스크립트에서 시간 소모가 큰 작업을 수행하는 동안 다른 코드를 계속 실행할 수 있는 기능을 의미합니다. 동기 처리와는 달리, 비동기 방식은 요청한 작업의 완료를 기다리지 않고 다음 작업으로 넘어가게 해 줍니다.
동기와 비동기의 차이
동기(Synchronous) 방식에서는 한 작업이 끝나야 다음 작업이 시작됩니다. 반면, 비동기(Asynchronous) 방식에서는 요청을 하고 그 결과를 기다리지 않고 바로 다음 작업을 실행할 수 있습니다. 이렇게 함으로써 웹 애플리케이션의 응답성을 높이고, 대기 시간을 최소화할 수 있습니다.
- 동기: 하나의 작업이 완료될 때까지 대기
- 비동기: 작업이 끝나지 않아도 다음 작업 실행
콜백 함수의 활용
비동기 처리를 구현하기 위한 전통적인 방법 중 하나는 콜백 함수를 사용하는 것입니다. 콜백 함수는 다른 함수에 인자로 전달되어 특정 시점에서 호출되는 함수입니다. 그러나 콜백 함수를 사용할 경우 “콜백 지옥”이 발생할 수 있습니다. 이는 중첩된 함수 호출로 인해 코드가 복잡해지고 가독성이 떨어지는 현상을 가리킵니다.
예를 들어, 다음과 같은 코드가 있다고 합시다:
function fetchData(callback) {
setTimeout(() => {
const data = "데이터 수신 완료";
callback(data);
}, 1000);
}
fetchData((data) => {
console.log(data);
});
이 경우, fetchData 함수가 호출되고, 1초 후에 콜백이 실행됩니다. 하지만 추가적인 비동기 작업이 필요할 때, 이러한 중첩은 코드의 복잡성을 증가시킬 수 있습니다.
Promise의 등장
이러한 문제를 해결하기 위해 등장한 것이 바로 프로미스(Promise)입니다. 프로미스는 비동기 작업의 완료 상태 및 결과 값을 나타내는 객체로, 성공(resolve) 또는 실패(reject) 상태를 기반으로 결과를 반환합니다. 이를 통해 더 깔끔하고 읽기 쉬운 코드를 작성할 수 있습니다.
const fetchDataPromise = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "데이터 수신 완료";
resolve(data); // 성공
}, 1000);
});
};
fetchDataPromise()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
위의 코드에서 promise를 통해 비동기 작업의 결과를 다루는 방식이 더욱 명확해졌습니다. 또한, 여러 개의 비동기 작업을 연결하는 “프로미스 체이닝”을 통해 코드의 가독성 또한 향상되었습니다.
프로미스의 상태
프로미스는 다음과 같은 세 가지 상태를 갖습니다:
- Pending: 초기 상태, 이행되지도 거부되지도 않은 상태
- Fulfilled: 비동기 작업이 성공적으로 완료된 상태
- Rejected: 비동기 작업이 실패한 상태
프로미스 상태를 기반으로 사용하는 후속 처리 메서드는 다음과 같습니다:
- .then(): 비동기 작업이 성공적으로 완료된 경우 실행됩니다.
- .catch(): 비동기 작업이 실패한 경우에 호출됩니다.
- .finally(): 작업의 성공 여부와 관계없이 항상 실행됩니다.
Promise.all()과 Promise.race()
여러 개의 프로미스를 동시에 처리하고 싶을 때는 Promise.all()이나 Promise.race()를 사용할 수 있습니다. Promise.all()은 모든 프로미스가 이행될 때까지 기다린 후 모든 결과를 배열 형태로 반환합니다. 반면, Promise.race()는 가장 먼저 완료된 프로미스의 결과를 반환합니다.
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'foo'));
Promise.all([promise1, promise2]).then((values) => {
console.log(values); // [3, 'foo']
});
위 예시에서는 두 개의 프로미스를 동시에 처리하고 결과를 출력합니다.
async/await로 간결하게
자바스크립트에서는 async/await 구문을 통해 프로미스를 더욱 쉽게 다룰 수 있습니다. async 함수 내에서 await 키워드를 사용하면 비동기 작업이 완료될 때까지 기다릴 수 있으므로, 마치 동기 코드처럼 코드를 작성할 수 있습니다.
async function getData() {
const data = await fetchDataPromise();
console.log(data);
}
getData();
이처럼 async/await 구문을 활용하면 비동기 코드를 더욱 간결하고 이해하기 쉽게 표현할 수 있습니다. 이러한 방식은 코드의 가독성을 높이고, 유지보수 또한 수월하게 만들어 줍니다.

마무리
자바스크립트의 비동기 처리 방식은 웹 개발에서 매우 중요한 요소입니다. 특히, 콜백 함수, 프로미스, 그리고 async/await의 사용법을 잘 이해하고 활용한다면 더 나은 품질의 코드를 작성할 수 있을 것입니다. 비동기 프로그래밍 기술을 익혀 나가면서, 효율적인 웹 애플리케이션 개발에 한 걸음 더 나아가 보시길 바랍니다.
자주 묻는 질문 FAQ
비동기 처리란 무엇인가요?
비동기 처리는 자바스크립트에서 시간이 많이 소요되는 작업을 진행하는 동안, 다른 코드가 계속 실행될 수 있도록 해주는 기능입니다.
동기와 비동기의 차이는 무엇인가요?
동기 방식은 한 작업이 끝날 때까지 대기하는 반면, 비동기 방식은 작업이 진행 중이라도 다음 작업을 실행할 수 있습니다.
콜백 함수는 어떻게 사용하나요?
콜백 함수는 다른 함수에 인자로 전달되어 특정 이벤트 발생 시 호출되는 함수입니다. 비동기 처리를 위해 많이 사용됩니다.
프로미스는 무엇인가요?
프로미스는 비동기 작업의 상태를 표현하는 객체로, 성공하거나 실패한 결과를 가지고 있습니다. 이를 통해 더 깔끔한 코드 작성을 가능하게 합니다.
async/await 구문은 어떤 역할을 하나요?
async/await 구문을 사용하면 비동기 작업을 동기적으로 처리할 수 있게 해주며, 코드 가독성이 향상되고 작성이 더 간단해집니다.