[JS] 콜백 (Callback)
01
콜백 (Callback) 이란?
자바스크립트는 비동기적으로 작동하며, 싱글 스레드에서 한 번에 하나의 작업만 처리할 수 있습니다.
이때 콜백은 다른 함수가 실행을 마친 후 실행되는 함수입니다.
콜백을 사용하면 비동기 작업이나 특정 작업이 끝난 후 결과를 받아서 다음 작업을 실행할 수 있습니다.
return과 Callback 은 다른 건가요?
: 네 return과 콜백함수는 다른 개념입니다.
✅ return
- 함수에서 값을 반환하는 데 사용되는 키워드입니다.
- 함수에서 값을 반환하는 키워드로, 함수 실행을 종료하고 값을 반환하여 다른 곳에서 사용할 수 있게 합니다.
✅ 콜백 함수 (Callback)
- 다른 함수에 인자로 전달되어 나중에 호출되는 함수입니다.
- 콜백 함수는 다른 함수에 전달되어, 해당 함수 내에서 나중에 호출되는 함수입니다.
따라서 return은 콜백 함수와 관계가 없고, 두 개는 다른 개념입니다.
02
Callback이 필요한 이유
콜백 함수를 사용하면 작업들이 순차적으로 실행됩니다.
예를 들어, 아래와 같이 콜백을 사용하면 하나의 작업이 끝난 후, 그 결과를 받아서 다음 작업을 진행할 수 있습니다.
function myMenu(callback) {
const menu = "불닭볶음면";
callback(menu);
}
function orderFood(menu, callback) {
console.log("오늘의 점심 메뉴는", menu);
callback();
}
function resultOrder() {
console.log("세팅 완료!");
}
myMenu(function (menu) {
orderFood(menu, function () {
resultOrder();
});
});
//결과:
//오늘의 점심 메뉴는 불닭볶음면
//세팅 완료!
✅ 만약 orederFood 함수에 callback을 주석처리 하게 된다면..
orderFood 함수가 콜백을 호출하기 전에 실행을 멈추지 않으므로,
resultOrder가 호출되지 않습니다. 콜백을 제대로 전달하지 않으면 실행 순서가 흐트러지게 됩니다.
03
Callback 만들어보기
아래처럼 Callback을 할 경우에는 순서대로 출력이 됩니다
function watchMovie(movie, callback) {
alert(`${movie} 영화를 시작합니다.`);
callback();
}
function movieFinished() {
alert('영화 시청이 끝났습니다.');
}
watchMovie('인셉션', movieFinished);
//결과:
//인셉션 영화를 시작합니다.
//영화 시청이 끝났습니다.
04
콜백 속 콜백
스크립트가 두 개 잇는 경우, 첫 번째 스크립트가 종료되고 두 번째 스크립트를 어떻게 순차적으로 불러올 수 있을까요
가장 자연스러운 방법으로는 아래코드처럼 콜백함수 안에 두 번째 함수를 호출하는 것입니다.
이렇게 하면 바깥의 MyMenu 함수가 실행이 완료된 후, 안쪽 orderFood 함수가 실행됩니다.
function myMenu(callback) {
const menu = "불닭볶음면";
callback(menu);
}
function orderFood(menu) {
console.log("오늘의 점심 메뉴는", menu);
}
myMenu(function (menu) {
orderFood(menu);
});
여기서 스크립트를 하나 더 불러오고 싶다면, 콜백 안에 콜백을 넣어 수행합니다.
콜백 안에 콜백을 넣는 동작은 단 몇 개뿐이라면 괜찮지만,
가독성이 떨어지고, 코드가 복잡해지므로 이런 방식을 자주 사용하는 것은 좋지 않습니다.
function myMenu(callback) {
const menu = "불닭볶음면";
callback(menu);
}
function orderFood(menu, callback) {
console.log("오늘의 점심 메뉴는", menu);
callback();
}
function resultOrder() {
console.log("세팅 완료!");
}
myMenu(function (menu) {
orderFood(menu, function () {
resultOrder();
});
});
05
에러 핸들링
지금까지의 예제에서는 데이터 로딩 실패나 에러 상황에 대한 처리가 없습니다!
언제나 우리는 로딩이 실패할 가능성을 고려해야 합니다.
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
document.head.append(script);
}
loadScript는 스크립트 로딩에 성공하면 callback(null, script)을, 실패하면 callback(error)을 호출합니다.
에러 우선 콜백 (Error-First Callback)
이 방식은 오류가 발생했을 때 첫 번째 인자에 오류 객체를 전달하고,
오류가 없다면 첫 번째 인자는 null로 두고, 두 번째 인자에 결과를 전달합니다.
loadScript('/my/script.js', function(error, script) {
if (error) {
// 에러 처리
} else {
// 스크립트 로딩이 성공적으로 끝남
}
});
오류 우선 콜백 스타일을 사용하면, 단일 콜백 함수에서 에러 케이스와 성공 케이스 모두를 처리할 수 있습니다
06
콜백지옥: 멸망의 피라미드
콜백 기반 비동기 처리는 꽤 쓸만해 보이기도 하고 실제로도 그렇습니다.
하지만 꼬리에 꼬리를 무는 동작들이 많아진다면 " 콜백지옥 "을 경험할 수 있습니다 👿
호출이 계속 중첩되면서 코드가 깊어지면서 만들어 내는 패턴을
" 콜백 지옥(Callback Hell) " 혹은 " 멸망의 피라미드(Pyramid of Doom) "라고 부릅니다.
loadScript('1.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('2.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('3.js', function(error, script) {
if (error) {
handleError(error);
} else {
// 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*)
}
});
}
})
}
});
이런 코딩방식은 좋지 않으므로 길어질 것 같다면 독립적인 함수로 분리해서 사용하는 방식도 있습니다.
하지만 이 방식도 코드가 여러 개로 쪼개지기 때문에 가독성이 좋지 않아 집니다..
loadScript('1.js', step1);
function step1(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('2.js', step2);
}
}
function step2(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('3.js', step3);
}
}
function step3(error, script) {
if (error) {
handleError(error);
} else {
// 모든 스크립트가 로딩되면 다른 동작을 수행합니다. (*)
}
};
이러한 콜백지옥(멸망의 피라미드) 문제를 해결하기 위해 나타난 가장 좋은 방법이 Promise입니다.
07
마무리
콜백 함수는 비동기 처리를 효율적으로 관리할 수 있지만, 중첩이 많아지면 코드가 복잡해지고 가독성이 떨어집니다.
이러한 문제를 해결하기 위해 Promise나 async/await을 활용하면 더 깔끔하고 직관적인 코드를 작성할 수 있습니다.
[JS] Promise
01Promise자바스크립트에서 비동기 작업이 끝날 때, 그 결과를 알려주는 "약속"과 같은 역할의 오브젝트입니다.예를 들어, 어떤 일이 잘 처리되면 결과를 알려주고, 문제가 생기면 에러를 알려주는
dev-watnu.tistory.com