함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수 callback function이라고 한다.
콜백 함수는 고차 함수에 의해 호출되며, 이때 고차함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
자바스크립트는 비동기 프로그래밍을 위한, 즉 이벤트를 처리하기 위해 만들어진 언어기 때문에
한 명령에 대한 응답을 기다리는 것 보다 다음 명령을 수행하기 위해서 콜백 함수를 사용한다.
자바스크립트 V8 엔진은 싱글 스레드이기 때문에 동시에 여러개의 명령을 수행할 수 없다.
따라서 한 명령의 응답이 오래 걸리게 된다면, 속도가 매우 느려지게 될 것이다.
하지만 비동기적 프로그래밍 방식으로 콜백함수를 사용하면 자바스크립트 엔진이 브라우저나 node.js에서 제공하는 Web API에게 작업을 맡기고, 다음 명령들을 수행하며 속도를 빠르게 할 수 있다.
브라우저에서 사용자가 언제 어떤 이벤트를 발생시킬지 예측이 불가능하다.
따라서 이런 이벤트를 관리하는 브라우저에게, 특정 이벤트가 발생할 때 실행하고 싶은 함수를 콜백 함수로 전달하면 된다.
서버에게 데이터 요청을 보냈을 때, 응답이 언제 올 지 모른다.
따라서 그런 서버 응답에 대한 처리도 비동기적으로 처리하면 좋다.
의도적으로 시간을 지연하는 setTimeout 같은 함수도 그 함수가 종료될 때 까지 기다리지 않고 비동기적으로 처리한다.
// 동기함수
console.log('1');
console.log('2');
console.log('3');
// 1 2 3
동기함수는 위와 같이 실행 순서가 순서대로 일어날 것으로 예측 했을 때, 그 예측과 맞아떨어진다.
왜냐면 중간의 명령문이 아무리 늦게 명령을 처리하더라도, 다음 명령이 수행되지 않기 때문이다.
// 비동기 함수
console.log('1');
setTimeout(() => {
console.log('2');
}, 1000);
console.log('3');
// 1, 3, 2 순으로 출력됨
비동기 함수는 실행 순서가 순서대로 일어나지 않고 1, 3, 2 처럼 예측 하기 어려운 결과를 가져온다.
중간의 명령문이 일을 수행할 때, 다음 명령문은 그를 기다리지 않고 바로 실행되기 때문이다.
콜백 지옥은 비동기 프로그래밍시 발생하는 문제로,
함수의 매개변수로 넘겨지는 콜백 함수가 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상을 말한다.
예시를 직접 보면 알게된다.
// 콜백 지옥 예시
step1(function (value1) {
step2(function (value2) {
step3(function (value3) {
step4(function (value4) {
step5(function (value5) {
step6(function (value6) {
// Do something with value6
});
});
});
});
});
});
step1~6은 어떤 일을 수행하는 함수이다.
먼저 step1이 그 처리가 끝나면 결과(value)를 받아와서 인자로 전달된 콜백 함수의 매개 변수로 넘겨준다.
이후 step2에서 어떤 처리를 하고, 다음 콜백 함수가 실행된다. ... 이하 반복
이를 반복하면 기묘한 피라미드모양(?)으로 코드가 작성되게 되고,
만약 여기서 에러 처리까지 포함되면 더욱 가독성이 떨어진다.
// 에러 처리까지 포함된 콜백 지옥
step1(function (err, value1) {
if (err) {
console.log(err);
return;
}
step2(function (err, value2) {
if (err) {
console.log(err);
return;
}
step3(function (err, value3) {
if (err) {
console.log(err);
return;
}
step4(function (err, value4) {
// ...
});
});
});
});
코드의 가독성이 떨어지면 유지 보수가 어려워지고, 실수가 발생할 가능성이 매우 높아진다.
따라서 위와 같이 콜백 지옥에 빠지지 않게 코드를 짜야하는데, 그때 Promise
객체가 사용된다.