Hanumoka, https://www.hanumoka.net/2018/10/24/javascript-20181024-javascript-callback/
참고 사이트에 내용을 개인적으로 복습하기 편하도록 재구성한 글입니다.
자세한 설명은 참고 사이트를 살펴보시기 바랍니다.
콜백 함수란 이름 그대로 나중에 호출되는 함수를 말합니다. 콜백함수라고 해서 그 자체로 특별한 선언이나 문법적 특징을 가지고 있지는 않습니다. 콜백 함수도 일반적인 자바스크립트 함수일 뿐입니다.
콜백 함수는 코드를 통해 명시적으로 호출하는 함수가 아니라, 개발자는 단지 함수를 등록하고, 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출하는 함수를 말합니다. 즉, 콜백 함수는 콜백 함수라는 유니크한 문법적 특징을 가지고 있는 것이 아니라, 호출 방식에 의한 구분입니다.
콜백 함수란 특정 함수에 전달되어 특정 함수의 어떤 조건에 의해 호출하는 함수라고 할 수 있습니다.
콜백 함수를 사용하는 이유는 자바스크립트에서 비동기 처리를 할 수 있기 때문입니다. 이 콜백 함수 방식은 자바스크립트에서 가장 오래된 비동기 메커니즘입니다.
자바스크립트 엔진은 싱글 스레드로 동작하기 때문에 한 번에 하나의 작업만을 수행할 수 있는 동기적 언어입니다. 비동기적으로 동작하기 위해서 자바스크립트 엔진을 작동시키는 브라우저 환경은 Event Loop, Event Queue, Web API를 활용해 비동기 함수와 비동기 함수를 처리하는 환경을 제공합니다.
비동기적 프로그래밍이 필요한 이유는 다음과 같습니다.
사용자 이벤트 처리
브라우저 화면에서 발생하는 사용자의 이벤트는 예측이 불가능하기 때문에 특정 이벤트가 발생하면 Web API에게 처리하고 싶은 내용을 콜백 함수에 담아 전달하게 됩니다.
네트워크 응답 처리
브라우저에서 서버에게 요청을 보냈을 때, 그 응답이 언제 돌아올 지를 알 수 없기 때문에 비동기적으로 처리해야 합니다.
파일을 읽고 쓰는 등의 파일 시스템 작업
의도적으로 시간 지연을 사용하는 기능
위와 같이 이벤트를 기다리거나 서버의 응답을 기다리기 위해 하나뿐인 스레드를 사용한다면 사용자는 멈춰져 있는 화면을 보게됩니다. 위와 같이 스레드의 블록킹을 야기하는 작업은 필수적으로 비동기적 프로그래밍을 해야 합니다.
비동기 처리를 하기 위해서는 비동기적으로 콜백 함수를 호출하는 함수에게 비동기적으로 호출되기를 원하는 코드를 콜백 함수에 담아서 전달해야 합니다.
function Sync(callback) {
callback();
}
console.log('------- Sync 호출 직전 -------');
Sync(() => console.log('동기적 콜백 함수'));
console.log('------- Sync 호출 이후 -------');
>> ------- Sync 호출 직전 -------
>> 동기적 콜백 함수
>> ------- Sync 호출 이후 -------
위는 동기적으로 콜백 함수를 호출합니다. 이처럼 단순히 아무 함수에게나 콜백 함수를 전달하여 호출시키는 것으로는 비동기적으로 콜백 함수를 호출 할수 없습니다.
다시 한번 강조하자면 자바스크립트에서 비동기 처리를 하려면 비동기적으로 콜백 함수를 호출하는 함수와 비동기적으로 호출되기를 원하는 콜백 함수가 필요합니다.
그러면 비동기적으로 콜백 함수를 실행하는 시스템 함수인 setTimeout()
함수를 알아보겠습니다.
setTimeout()
함수는 콜백 함수의 실행을 정해준 ms만큼 지연하는 대표적인 비동기 함수입니다.
function Async(callback, delay) {
setTimeout(callback, delay);
}
console.log('------- 호출 직전 -------');
Async(() => console.log('비동기적 콜백 함수'), 3000);
console.log('------- 호출 이후 -------');
>> ------- 호출 직전 -------
>> ------- 호출 이후 -------
>> 비동기적 콜백 함수
3초 뒤에 콜백 함수가 호출되는 것을 확인 할 수 있습니다. 만약 동기적인 프로그래밍에서 3초 뒤에 콜백 함수를 호출시키려 한다면, 3초를 자바스크립트의 하나뿐인 스레드가 카운팅을 하고 있어야 합니다. 즉, 프로그래밍이 멈추게 됩니다.
Async()
함수 내부에 setTimeout()
함수는 스레드가 해야할 동작을 Web API에게 위임시킴으로써 스레드의 블록킹을 피하게 해줍니다.
function Async(callback, delay) {
setTimeout(callback, delay);
}
console.log('------- 호출 직전 -------');
Async(() => console.log('비동기적 콜백 함수'), 0);
console.log('------- 호출 이후 -------');
>> ------- 호출 직전 -------
>> ------- 호출 이후 -------
>> 비동기적 콜백 함수
위 코드를 보면 Async()
함수에 지연 시간을 0
으로 설정하여 즉시 실행하도록 했습니다. 그 결과를 보면 3초의 지연 시간을 가졌을 때와 마찬가지로 맨 마지막에 호출되는 것을 확인 할 수 있습니다.
이러한 동작이 발생하는 이유는 Async()
함수 내부에 setTimeout()
함수로 전달된 콜백 함수는 javascript 실행 환경의 Web API에게 전달되고 Web API는 지연 시간을 카운팅합니다.
이후 지연 시간이 끝나면 Event Queue로 이 콜백 함수를 전달합니다. 이 때 Evnet Loop가 스레드의 동작이 모두 끝났는 지를 계속해서 확인하며 모든 동작이 끝나있을 때 Event Queue에 있는 콜백 함수를 스레드에게 전달합니다.
여기서 중요한 점은 setTimeout()
함수와 같은 비동기적으로 콜백 함수를 호출 시켜주는 함수는 전달된 콜백 함수를 현재 실행중인 스레드에서 뽑아내어 특정 장소에 보관하고 특정 조건을 만족시킬때 호출을 가능하게 한다는 점입니다.
setTimeout()
함수는 시간을 카운팅하는 기능 외에 콜백함수를 비동기 영역으로 넘기는 역할 또한 수행합니다.