반에 손석희를 좋아하는 동생이 callback 함수에 대해 물어봤다.
앞서 매우 많은 포스트에 콜백
이라는 단어를 썼지만 그저 매개변수처럼 작동하는 추상적인 개념으로만 알고 있을 뿐 설명하기엔 내 지식이 부족했다.
그래서 하나하나 매우매우 쉽게 짚어보자
const
definition1 = "다른 함수의 '인자'로써 이용되는 함수."
const
definition2 = "어떤 이벤트에 의해 '호출'되어지는 함수."
즉, 함수는 JS 1급 객체이다
의 rule에 따라 이 callback "함수" 도 매개변수처럼 쓰일 수 있다.
1급 객체는 또 뭐임? 그니까 1급 시민 처럼 모든 것이 JS에서 자유롭게 상호작용이 가능하다는 뜻이다.
예를 들어
1. 변수나 데이터 구조안에 담을 수 있고
2. 매개변수로 전달 할 수 있고
3. 리턴 값으로 사용할 수 있다 정도가 되겠다.
그럼 우선 정의 1과 2의 예시를 한큐에 봐보자
(아래 코드를 그래도 VScode로 가져가서 개발자도구를 열어서 보면 된다. 실행하기 전 머리속으로 디버깅 실시 후 돌려보자)
// 1. 콘솔에 hello를 출력하는 함수
function printHello(){
console.log('hello');
}
// 2. 콘솔에 bye를 출력하는 함수
function printBye(){
console.log('bye');
}
// 3. 특정 함수를 매개변수로 받아서 3초 뒤에 실행하는 함수
function sleepAndExecute(sleepTimeSecond, callback){
//sleepTimeSecond 초 만큼 대기 후 callback 실행
setTimeout(()=>callback(), sleepTimeSecond)
}
// 4. 3000micro second 뒤에 hello 출력하기
console.log(sleepAndExecute(3000, printHello))
// 5. 5000micro second 뒤에 bye 출력하기
console.log(sleepAndExecute(5000, printBye))
sleepAndExecute
의 매개변수가 2개가 있고 그중 하나로 callback 함수가 들어있는 것을 확인할 수 있다. 이것이 1번 정의setTimeout
함수가 실행될 때 callback() 함수를 실행한다고 나와있다. 즉 setTimeout
함수라는 이벤트에 의해 callback함수가 호출되어진다는 것이다.function findUserAndCallBack(id, cb) {
const user = {
id: id,
name: "Username" + id,
email: id + "@test.com",
};
cb(user);
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
findUserAndCallBack
함수를 보면 알 수 있듯 벌써 cb
함수가 매개변수로 들어가있다.findUserAndCallBack
함수안에 const user
라는 field값이 존재한다. 거기에 매개변수로 받은 id, name, email을 저장하고 cb
함수를 호출한다 라고 정의(function)되어있다.findUserAndCallBack
함수를 호출하는 것을 볼 수 있다. id는 1로 주었고 cb
라고만 명시했던 것을 함수 호출 부분에서 명시해둔 것을 알 수 있다.그니까 콜백함수가 뭐냐
"function 정의하는 부분에서 간단하게 cb나 callback이라고 명시해두고 나중에 함수를 호출 할 때 그 함수가 어떤 함수다"
라고 알려주려고 개발자들이 편하려고 쓰는거다 근데 이게 어떻게 가능하다고?
JS에서 함수는 1급객체의 특성을 갖고있기 때문
function findUser(id) {
let user;
setTimeout(function () {
console.log("waited 0.1 sec.");
user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
}, 100);
return user;
}
const user = findUser(1);
console.log("user:", user);
function findUserAndCallBack(id, cb) {
setTimeout(function () {
console.log("waited 0.1 sec.");
const user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
cb(user);
}, 100);
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
각각 아래와 같이 결과값이 나왔을 것이다. 그런데 자세히 살펴보면 밑에가 동기통신 코드처럼 보인다 왜? 위에부터 아래로 순서대로 실행되었기 때문에 하지만 여기서 JS의 구조를 조금 이해해야 한다.
바로 setTimeout과 같은 비동기 코드를 만나면 일단 다른 queue로 미뤄둔다 왜?
이를 계산할 thread라는 녀석이 하나밖에 없기 때문에
그렇다 JS는 싱글 thread다! 그래서 여러일을 한큐에 못 하고 이거끝내고 다른걸 해야한다. 그럼 매우 큰 일을 하루죙일 잡고있어? 그럼 사용자 입장에선 흰페이지를 꽤 오래보고 있어야 하기에 빨리빨리 처리되는 것 부터 실행 후 나중에 queue에 있는 녀석들을 끄집고와서 처리한다.
즉, 아래 코드가 순서대로 작동해서 동기처럼 보이겠지만 비동기적으로 처리해야만 동기처럼 error가 안 나고 작동이 되는 역설적인 현상이 나타난 것이다.
위의 코드를 설명하기위해 사족이 길었는데 무튼
콜백함수는 비동기 통신에서도 자주 쓰인다!!