서론
JavaScript에서 비동기 프로그래밍은 중요한 주제 중 하나이다. 비동기 작업은 코드의 흐름을 방해하지 않고, 동시에 여러 작업을 처리할 수 있게 해준다. 이러한 비동기 작업을 효율적으로 처리하기 위해 Promise와 Async/Await라는 두 가지 주요 도구가 있다. 이 글에서는 Promise가 무엇인지, 그리고 Async/Await와의 차이점이 무엇인지에 대해 좀 더 깊이 있게 다루고자 한다.
Promise
JavaScript는 기본적으로 단일 스레드로 동작하기 때문에, 코드가 순차적으로 실행된다. 그러나 웹 애플리케이션에서는 네트워크 요청, 파일 입출력, 타이머 등 시간이 걸리는 작업을 처리해야 하는 경우가 많다. Promise는 비동기 작업이 완료되었을 때 결과를 사용할 수 있게 해주는 객체이다. Promise 따라서 비동기 작업의 결과를 나중에 사용할 수 있게 해준다. 기본적으로 Promise는 다음 세 가지 상태를 가진다:
- 대기(Pending): 비동기 작업이 아직 완료되지 않은 상태.
- 이행(Fulfilled): 비동기 작업이 성공적으로 완료된 상태.
- 거부(Rejected): 비동기 작업이 실패한 상태.
Promise는 비동기 작업이 완료되면, resolve 또는 reject 함수를 호출하여 작업이 성공했는지 실패했는지를 나타낸다. 성공적으로 완료되면 then 메서드를 통해 결과값을 사용할 수 있고, 실패할 경우 catch 메서드를 통해 에러를 처리할 수 있다.
const promise = new Promise((resolve, reject) => {
// 비동기 작업 수행
const success = true;
if (success) {
resolve('작업 성공');
} else {
reject('작업 실패');
}
});
promise
.then((result) => {
console.log(result); // '작업 성공'
})
.catch((error) => {
console.error(error); // '작업 실패'
});
Promise의 가장 큰 장점은 콜백 함수의 중첩으로 인해 발생하는 '콜백 지옥'을 피할 수 있다는 점이다. 복잡한 비동기 작업도 Promise를 사용하면 가독성이 높은 코드로 관리할 수 있다.
Async/Await: 비동기 작업을 동기처럼
Async/Await는 ES2017(ES8)에 도입된 비동기 프로그래밍 문법이다. 사실 Async/Await는 Promise를 기반으로 동작한다. 그러나 코드의 구조가 더 간결하고 명확해지기 때문에, 동기적으로 작성된 코드처럼 보이게 하는 것이 큰 장점이다.
Async/Await를 사용하면, 마치 비동기 작업이 동기적으로 처리되는 것처럼 코드를 작성할 수 있다. 아래는 Async/Await를 사용한 예시이다:
async function fetchData() {
try {
const result = await promise;
console.log('결과:', result);
} catch (error) {
console.error('에러 발생:', error);
}
}
fetchData();
위 코드에서 await 키워드는 Promise가 이행되기를 기다린다. 이 때 Promise가 이행되기 전까지는 다음 코드가 실행되지 않는다. 만약 Promise가 거부되면, catch 블록을 통해 에러를 처리할 수 있다. 이처럼 await 키워드를 사용하면, 마치 동기 코드처럼 비동기 작업을 처리할 수 있다. 하지만 모든 상황에서 await을 사용하는 것은 적절하지 않다. 여러 비동기 작업을 동시에 처리해야 하는 경우에는 Promise.all이나 Promise.allSettled와 같은 방법을 사용하는 것이 더 효율적일 수 있다.
Promise.all은 여러 개의 Promise를 병렬로 실행하고, 모든 Promise가 완료될 때까지 기다린다. 하지만 하나라도 실패하면 전체가 실패로 간주된다. 반면 Promise.allSettled는 모든 Promise의 완료 여부에 상관없이 결과를 반환해 준다. 즉, 하나의 Promise가 실패하더라도 나머지 Promise의 결과를 확인할 수 있다.
Promise와 Async/Await의 차이점
두 방법 모두 비동기 작업을 처리하기 위해 사용되지만, 그 사용 방식에는 차이가 있다.
- 가독성: Promise는 then과 catch를 통해 비동기 작업의 결과를 처리하는 반면, Async/Await는 비동기 작업을 마치 동기 작업처럼 처리할 수 있어 가독성이 높다. 특히 여러 개의 비동기 작업이 연속적으로 실행되어야 하는 경우, Async/Await가 더 직관적이다.
- 에러 처리: Promise는 catch 메서드를 통해 에러를 처리한다. 반면, Async/Await는 try...catch 구문을 사용하여 에러를 처리한다. 이 방식은 동기 코드에서 사용하는 것과 동일하기 때문에, 코드 구조를 단순화할 수 있다.
- 비동기 작업의 병렬 처리: Async/Await를 사용할 때, 여러 비동기 작업을 병렬로 처리하고 싶다면 Promise.all이나 Promise.allSettled와 같은 메서드를 함께 사용해야 한다. 그렇지 않으면, 각각의 await가 순차적으로 실행되기 때문에 병렬 처리가 되지 않는다.
async function fetchMultipleData() {
const [result1, result2] = await Promise.all([promise1, promise2]);
console.log(result1, result2);
}
Promise와 Async/Await 간의 선택
대부분의 경우, Async/Await가 더 직관적이고 가독성이 좋기 때문에 선호된다. 하지만 상황에 따라 Promise를 사용하는 것이 더 적절할 수 있다. 예를 들어, 여러 개의 비동기 작업을 병렬로 처리해야 하는 경우, 또는 비동기 작업을 조합하여 복잡한 로직을 구성해야 하는 경우에는 Promise가 더 유리할 수 있다.
결론적으로, Promise와 Async/Await는 각각의 장단점을 가지고 있으며, 상황에 맞게 적절히 사용하는 것이 중요하다. 이 글이 JavaScript의 비동기 프로그래밍을 이해하는 데 도움이 되길 바란다.
'JS' 카테고리의 다른 글
JavaScript 이벤트 루프 동작방식: Microtask Queue, Macrotask Queue (0) | 2024.11.21 |
---|---|
[JS] Javascript에서 동기함수와 비동기함수의 차이 (0) | 2024.07.25 |
[JS] Javascript에서의 FP (0) | 2024.07.24 |
[JS] Javascript에서의 모듈 시스템 (1) | 2024.07.23 |
[JS] Javascript에서의 OOP (0) | 2024.07.22 |