Promise
기존 콜백 패턴의 단점
예시의 xhr.load 이벤트 핸들러 프로퍼티에 바인딩한 이벤트 핸들러는 아래의console.log보다 항상 늦게 실행된다.
const get = url => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status == 200) {
//1. 서버의 응답을 상위 스코프의 변수에 할당한다.
todos = JSON.parse(xhr.response);
} else {
console.error(`${xhr.status} ${xhr.statusText}`);
}
}
}
// id가 1인 post를 취득
get('https://jsonplaceholder.typicode.com/posts/1');
console.log(todos); // 2. undefined
만약 console.log(todos)
가 실행되기 전에 load
이벤트가 발생했더라도, 콜스택에 쌓인 실행컨택스트를 모두 실행한 후에야 이벤트 루프가 태스크 큐에 저장된 load 이벤트 핸들러를 콜스택으로 푸시하므로 이벤트 핸들러가 console.log 이전에 실행될 수는 없다.
따라서 비동기 함수는 비동기 처리 결과를 외부에 반환할 수 없고, 상위 스코프의 변수에 할당할 수 없다.
비동기 처리 결과에 대한 후속 처리를 수행하는 콜백 함수를 전달하는 게 일반적이다
비동기 처리 결과에 대한 후속 처리를 수행하는 콜백 함수가 결과를 가지고 다시 비동기 함수를 호출한다면 콜백 함수 안에서 다시 콜백 함수를 불러 복잡해진다 ⇒ 콜백 헬
: 코드의 가독성이 떨어지며 실수하기 쉽다
에러는 호출자 방향(즉, 콜스택의 바로 아래 실행컨텍스트)으로 전파된다. 그런데 setTimeout에서 받아온 콜백함수의 호출자는 setTimeout이 아니다. setTimeout함수는 호출된 후 콜백함수의 실행을 기다리지 않고 즉시 종료되어 콜스택에서 제거되고, 콜백함수는 타이머 만료 후 태스크 큐에 등록되었다가 콜스택이 비었을 때 콜스택에 푸시된다. 따라서 에러가 발생했을 때 받아줄 호출자가 없다