[Javascript] 콜백
콜백함수
콜백함수란 어떤 고차함수에 해당 함수를 인자로 넘겨주어 사용되는 함수를 말함
어떤 코드가 비동기적으로 실행될 때 콜백함수를 유용하게 사용할 수 있음
인자로 넘겨받은 스크립트를 html문서에 추가시켜주는 함수가 있다고 가정
function load(src){
let script = document.createElement("script");
script.src = src;
document.head.append(script);
}
//함수를 실행
load("scripts/scriptOne.js");
위와같이 load라는 함수를 실행하면 비동기적으로 동작함
load로 불러온 "scripts/scriptOne.js" 에 myFunc(){} 라는 함수가 있다고 가정
function load(src){
let script = document.createElement("script");
script.src = src;
document.head.append(script);
}
//함수를 실행(myFunc()함수가 scriptOne.js 에 정의되어 있음)
load("scripts/scriptOne.js");
//load가 비동기적으로 실행되므로 오류 발생할 수 있음
myFunc();
위에 코드를 실행시 load가 비동기적으로 실행되므로 load의 작업이 끝날때 까지 밑에 코드들이 기다려 주지 않으므로 scriptOne.js 가 불려오지 않은 상태에서 myFunc()함수가 실행되어 오류가 발생할 수 있음
이러한 문제를 해결하기 위해 callback함수를 사용
function load(src,callback){
let script = document.createElement("script");
script.src = src;
//스크립트가 로드되면 callback함수를 실행
script.onload = () => {
callback();
}
document.head.append(script);
}
//함수를 실행(callback함수를 2번째 인자로 전달)
load("scripts/scriptOne.js",function(){
//로드가 된 상태에서 myFunc()을 호출하므로 정상적으로 실행
myFunc();
});
위와같이 콜백함수를 이용하면 로드가 완료된 상태에서 동기적으로 myFunc를 호출할 수 있음
에러 핸들링
콜백 함수에서의 에러 핸들링은 다음과 같이 할 수 있음
function load(src,callback){
let script = document.createElement("script");
script.src = src;
//스크립트가 로드되면 callback함수에 script 전달
script.onload = () => callback(null,script)
//스크립트를 불러오는데 에러가 발생하면 에러 전달
script.onError = () => callback(new Error("${src} 로드 중 에러발생"))
document.head.append(script);
}
//함수를 실행(callback함수를 2번째 인자로 전달)
load("scripts/scriptOne.js",function(error,script){
//error가 존재할 시 에러 핸들링 실행
if(error){
//...
}else{ //정상적으로 스크립트 로드시
}
});
콜백 지옥
아래와 같이 콜백 함수를 여러번 중첩해야 하는 상황이 있을 수 있음
function load(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);
}
load("scripts/scriptOne.js",function(error,script){
if(error){
//...
}else{
//scriptOne.js의 호출이 완료되면 scripts/scriptTwo.js를 호출
load("scripts/scriptTwo.js",function(error,script){
if(error){
}else{
}
})
}
});
위의 코드는 중첩이 한번밖에 발생하지 않아서 별 문제가 없지만 중첩이 수십개가 될 경우 코드가 오른쪽으로 끝없이 늘어나 코드 분석 및 유지보수가 매우 힘들어질 수 있음.
이러한 현상을 '콜백지옥' 또는 '멸망의 피라미드' 라고 함.
이러한 콜백지옥의 코드를 만들지 않기위해 아래와 같이 변경할 수 있음
function load(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);
}
//scriptOne을 로드하고 func1을 호출
load("scripts/scriptOne.js",func1);
//func1이 호출되면 scriptTwo가 호출되고 func2가 호출
function func1(error,script){
if(error)
//...
else
load("scripts/scriptTwo.js",func2);
}
//모든 스크립트가 로딩되면 실행
function func2(error,script){
if(error)
//...
else
//...
}
위와같이 함수를 분리해 놓으면 콜백지옥에 빠지지 않게 콜백 함수를 중첩해서 호출할 수 있음
하지만 이렇게 생성한 함수들은 재사용 하기도 힘들다는 단점이 있음.
이러한 함수들을 따로 분리해놓지 않고도 콜백 지옥을 피하는 방법은 '프라미스(Promise)' 를 사용하는 것임(next)
참조: https://ko.javascript.info/callbacks