ES6에서 비동기 처리를 위한 패턴으로 프로미스를 도입한다.
이는 전통적 콜백 패턴이 가진 단점을 보완, 비동기 처리 시점을 명확히 표현할 수 있다는 장점을 가진다.
1. 비동기 처리를 위한 콜백 패턴의 단점
전통적인 비동기 처리의 예시를 보자.
const get = (url, successCallback, failureCallback) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
// todos = JSON.parse(xhr.response);
successCallback(JSON.parse(xhr.response));
} else {
// console.error(`${xhr.status} ${xhr.statusText}`);
failureCallback(xhr.status);
}
};
};
get(url, console.log, console.error);
비동기 함수는 처리 결과를 외부에 반환할 수 없고, 상위 스코프 변수에 할당할 수도 없다.
따라서 비동기 함수 처리 결과에 대한 후속 처리는 내부에서 수행해야 하므로, 그를 위한 콜백 함수를 또! 전달해주어야 한다.
이렇게 콜백 함수 호출이 중첩되어 복잡도가 높아지는 현상을 콜백 헬이라 한다.
2. 프로미스의 생성
const promise = new Promise((resolve, reject) => {
if (비동기 성공) {
resolve('result');
} else {
reject('failure reason');
}
});
프로미스는 pending, fulfilled, rejected 3가지의 비동기 처리 상태 정보를 갖는다.
이 상태는 resolve, reject 함수를 호출하는 것으로 결정된다.
3. 프로미스의 후속 처리 메서드
프로미스는 후속 메서드 then, catch, finally를 제공한다.
프로미스 비동기 처리 상태가 변화하면 콜백 함수가 선택적으로 호출된다.
모든 후속 처리 메서드는 프로미스를 반환하며, 비동기로 동작한다.
new Promise(resolve => resolve('fulfilled'))
.then(v => console.log(v), e => console.log(e)); // fulfilled
new Promise((_, reject) => reject(new Error('rejected')))
.catch(e => console.log(e)); // Error: rejected
// finally 메서드의 콜백 함수는 프로미스 성공 실패 여부에 상관없이 무조건 한 번 호출된다.
new Promise(() => {}).finally(() => console.log('finally')); // finally
4. 프로미스의 정적 메서드
Promise.all / Promise.race
여러 비동기 처리를 병렬 처리할 때 쓰인다.
const req1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const req2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const req3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));
Promise.all([req1(), req2(), req3()]).then(console.log); // [1, 2, 3] 약 3초 소요
Promise.race([req1(), req2(), req3()]).then(console.log); // 3
5. 마이크로태스크 큐
setTimeout(() => console.log(1), 0);
Promise.resolve().
.then(() => console.log(2))
.then(() => console.log(3));
// 2 -> 3 -> 1
프로미스의 후속 처리 메서드의 콜백 함수는 태스크 큐가 아니라 마이크로태스크 큐에 저장된다.
콜백 함수나 이벤트 핸들러를 일시 저장한다는 점에서 태스크 큐와 동일하지만 더 우선순위가 높다.
즉, 이벤트 루프는 콜 스택이 비면 먼저 마이크로태스크 큐에서 대기하는 함수를 실행한다.
'모던자바스크립트-DeepDive' 카테고리의 다른 글
9. 비동기 프로그래밍 (0) | 2024.10.04 |
---|---|
8. 타이머 (0) | 2024.10.04 |
7. 이벤트 (0) | 2024.10.03 |
6. 브라우저의 렌더링 과정 (0) | 2024.10.03 |
5. 배열 (2) | 2024.10.02 |