자바스크립트는 이벤트 중심의 언어이기에 이벤트의 값이 반환될 때까지 기다리지 않고 다음의 이벤트를 진행하게 된다.
때문에, API 요청과 같이 비동기적인 함수를 실행할 경우 특별한 처리를 해주지 않으면 원하는 대로 동작하지 않을 수 있다.
이러한 문제를 해결하기 위해 나타난 방법이 콜백이다.
블록킹을 방지하여 싱글 스레드가 논블록킹으로 동작하게 하는 프로그래밍이다.
동기식(synchronous)
순차적, 직렬적으로 작업(task)을 수행한다.
👉 서버에게 요청을 한 뒤 데이터를 받아야 이어서 데이터를 가지고 처리를 할 수 있다.
👉 blocking
비동기(asynchronous)
병렬적으로 작업을 수행한다.
👉 서버에게 데이터를 요청 한 후 응답을 기다리지 않고 바로 다음 작업을 수행한다
👉 non-blocking
자바스크립트는 싱글 스레드 언어이기에 비동기적 프로그래밍을 구현하기 위해서비동기 작업을 병렬적으로 수행하기 위해 Web API와 Callback Queue를 이용한다.
싱글 스레드 👉 한 번에 한 가지 일만 실행할 수 있다.
나중에 호출
되는 함수이다.
우선, 자바스크립트에서 함수는 객체이고, 함수는 인자를 가질 수 있다.
이때, 인자로 대입되는 함수를 콜백함수라고 하는 것이다.
어떤 이벤트가 발생했거나 특정 시점에 도달했을 때, 시스템에서 호출하는 함수이다.
👇 이벤트 핸들러를 처리하는 코드를 살펴보자.
<button onclick="onClick">버튼</button>
<script>
function onClick(){
alert("버튼을 누르셨습니다");
}
</script>
HTML의 onClick함수가 브라우저의 Javascript API에서 DOM 이벤트 핸들러에 등록되고, 해당 버튼을 클릭하면 이벤트 핸들러가 콜백 함수 onClick
을 호출한다.
즉, 특정 함수에 전달되어 있는 함수가 어떤 조건에 의해 호출되는 함수이다.
앞서 말했듯이 콜백함수는 일반적으로 다른 함수에 넘기거나 객체의 프로퍼티로 사용하고, 보통 익명함수로 사용한다.
콜백함수도 일반적인 함수
라는 것을 명심하자.
function whereAsync(callback){
callback();
}
console.log('whereAsync 호출 전');
whereAsync(function(){
console.log('비동기??');
});
console.log('whereAsync 호출 후');
단순하게 함수에 콜백 함수를 전달하는 것만으로는 비동기적인 수행이 불가능하다.
따라서 비동기 프로그래밍을 위해서는 2가지가 필요하다는 것을 알았다.
비동기적으로 콜백 함수를 호출하는 함수
비동기적으로 호출되기를 원하는 콜백 함수
setTimeout( ) setInterval( ) clearInterval( )에서 자세한 예제를 다루고 있다.
const printFruitDelay = (fruit, callback) => {
setTimeout( // 타이머 API
() => {
console.log(fruit, time);
callback(); // 콜백 함수를 전달받아 실행
},2000); // 2초
}
const printFruits = () => {
printFruitDelay("apple", () => {
printFruitDelay("orange", () => { // 콜백 안에서 콜백을 실행
printFruitDelay("grape", () => {})
})
})
}
printFruits();
비동기 작업들의 처리 순서를 보장하기 위해서 printFruitDelay라는 콜백 함수
내부에서 익명함수를 콜백함수로 인자
로 받는 printFruits 비동기 함수
를 호출하였다.
순서대로 apple 👉 orange 👉 graphe가 출력되지만, 콜백 안에 콜백을 넣는 방식은 지양해야 한다.
콜백 함수를 사용할 때, 비동기 작업이 실패될 수도 있으므로 이에 대한 에러를 핸들링 해야 한다.
const handleError = (src, callback) => {
// ...src로 작업 수행
if (비동기 작업 성공) {
callback(null, value); // src를 이용한 결과값
} else { // 에러가 발생한 경우
callback(error, null);
}
}
handleError(src, (err, data) => {
if (err) {
// 에러 처리
// err 👉 error
// data 👉 null
} else {
// Do something
// err 👉 null
// data 👉 value
}
})
에러가 발생하면 callback(error, null)
를 호출하고, 성공하면 callback(null, value)
를 호출하여 오류 우선 콜백을 사용한다.
많이 들어봤을 콜백 지옥이다.
복잡한 비동기 작업이 들어왔을 때, 여러 개의 콜백 함수를 중첩시켜 사용할 때 나타나는 문제이다.
// step1부터 6까지 순서대로 실행되어야 하는 경우
step1(function (value1) {
step2(function (value2) {
step3(function (value3) {
step4(function (value4) {
step5(function (value5) {
step6(function (value6) {
// Do something use value6
});
});
});
});
});
});
가독성도 떨어지고, 에러 및 디버깅, 유지보수에도 좋지 않다.
📚 학습할 때, 참고한 자료 📚