[JavaScript] 콜백함수(Callback function)과 비동기처리
콜백함수(Callback function)를 대략적인 느낌으로 알고있긴 하지만 누군가에게 설명할 수는 없어 한번 정리해보고자 합니다. 갑자기 정리하게된 이유는 Promise / async-await과 같은 비동기처리 방식이 콜백함수에서부터 나오게 되기 때문입니다. 콜백함수를 정확히 모른다면 저 위의 두 개념도 정확히 설명하지 못할 것이기 때문입니다.
Callback은 '나중에 호출된다'는 의미입니다. Call-after라고도 하기도합니다. 즉, 콜백함수는 '나중에 호출되는 함수'입니다. 엥 모든 함수는 나중에 호출되지 않나요?
void foo(){
cout << "Test" << endl;
}
void main() {
foo();
return;
}
위와 같은 C++ 코드를 봅시다. 우리는 "Test"라는 string이 몇번 호출되고 몇번 출력되는지 예상할 수 있습니다. main에서 1번 호출되어서 Test 하나 콘솔에 찍고 프로그램 종료하겠네요.
그럼 '나중에 호출되는' 콜백함수는 뭘까요? 아주 간단한 예시를 들겠습니다.
studentList.map((item)=>{<li>item.name</li>})
가장 흔히 쓴다고 생각하는 map을 볼까요. map안에는 잘 보시면 함수
(item)=>{ <li> item.name </li> }
가 들어있습니다.
item을 받으면 item의 name을 띄우는 함수인데요. map에 의해 studentList안의 아이템들의 이름이 쭉~뜨게 됩니다. 근데..이 (item)=>{ <li> item.name </li>} 함수가 몇번 호출될지, 무엇을 출력할지 알 수 있나요?
모릅니다. 우리는 그냥 함수만 넣어주고, 나중에 studentList에 오는거에 따라 출력이 정해지게 될 것입니다. 이 함수를 '나중에 호출되는' 콜백함수라고 합니다.
좀 더 명확하게 설명하자면, 콜백함수는 '인수(parameter)로 넘겨줄 수 있는 함수'입니다. map이나 forEach도 콜백함수를 받습니다. setTimeOut (지정한 시간 뒤에 인수로 주어진 콜백함수 실행)과 addEventListener (이벤트가 발생하면 인수로 주어진 콜백함수 실행)도 콜백함수 씁니다.
콜백함수의 정의는 몰라도 사실 여러분은 이미 많이 쓰고 있었을지도 모릅니다 ㅎㅎ
그럼 이게 왜 비동기처리에 쓰이며, Promise나 async await과 관련있을까요?
예시를 하나 들어보겠습니다.
setTimeOut함수는 첫번째 인자로 콜백함수(실행시킬 함수), 두번째 인자로 시간(몇초 뒤에 실행할건지)을 받습니다.
이 setTimeOut이 받는 콜백 함수를 '일정 시간 뒤에 실행'하게 하면 비동기를 구현할 수 있습니다. 비동기 작업을 호출하면서, 끝났을 때 실행할 콜백 함수를 넘겨주면 성공적으로 일정 시간 뒤에 콜백함수를 호출할 수 있습니다.
여기서 '비동기(async)'가 뭔지 궁금할 수 있습니다. 간단히 말하면 앞의 일이 끝나지 않아도 다음 작업을 계속하는 처리과정으로 이해하면 쉬울 것 같습니다. 예를 들어 서버에 게시글을 띄우라는 요청을 보냈는데 응답이 오는데까지 꽤 많은 시간이 걸린다고 합시다. 그동안 페이지가 멈춰있으면... 응답 처리하기는 쉽겠지만 사용자는 멍때리고 있어야겠죠? 만약 서버에 요청해야하는 것들(API)이 많을수록 페이지는 오랫동안 얼어있을거에요.
비동기 처리는 고려하는 사항이 많은대신 페이지의 성능을 엄청 높여줍니다. 위의 setTimeOut 예시를 다시 볼게요! 몇초 뒤에 콜백함수를 실행해주세요! 하고 넘겨주면 그 몇초동안 다른 작업을 하다가, 시간이 되면 아까 그 콜백함수를 실행하면 되는 겁니다. 즉, 콜백함수로 비동기 처리를 하는 코드를 구현할 수 있습니다.
여담이지만 자바스크립트는 싱글 스레드 언어입니다. 어떻게 콜백 함수로 비동기가 가능할까요? 요건 다른 포스트에서 다루겠습니다.
사실...콜백함수로 비동기 처리를 하는 코드는 많지 않습니다. 특히, 코드의 길이가 길어지고 요청의 양이 많이지고 다뤄야할 에러의 종류가 많아질수록 콜백함수는 비동기 처리의 방법으로 적절하지 않습니다.
위 그림과 같이 콜백지옥(Callback Hell)에 빠지게 됩니다. 가독성도 떨어지고...수정하기도 힘들고....콜백함수 말고 다른건 없을까요?
다음 포스트에서는 이런 문제를 해결해줄 Promise 객체를 다루겠습니다. 더 나아가 async / await 문법에 대해서도 알아보도록 하겠습니다.
감사합니다!