콜백 함수(call-back function)
드디어 문제의 콜백 함수를 다룰 때가 왔습니다. 우선, 콜백 함수는 단 한 문장으로 쉽게 정의하기보다는 여러 가지 개념이 한데 어우러져 이해해야 하는 개념이니, 차근차근 아티클을 읽고 다른 코드 예시나 구글링을 통해 여러 개념을 반복해서 접해봅시다. 끈기 있게 공부하는 것이 중요합니다.
우선, 콜백 함수를 사용한다는 것은 입출력 모델(I/O model)의 관점에서 봤을 때 Event Driven, Non-Blocking을 사용한다는 특징을 갖습니다. 콜백 함수라는 것이 "어떤 형식으로 코드를 작성하면 콜백 함수다!"라고 정의하기 보다는, 이러한 특성을 갖는 함수라고 이해해야 합니다.
Event Driven Function
Event Driven 함수로서의 성질을 설명하기 전에, 더 쉽게 설명하기 위해서 Event Driven이 아닌 함수는 어떤 것을 의미하는지 생각해 봅시다. 우리는 앞서 기본적으로 함수를 선언한 다음, 다음과 같은 방식으로 함수를 호출했습니다.
function plus(x, y) {
return x + y;
}
plus(99, 283);
너무 간단해보이지만, plus( )라는 함수를 '어떤 방식으로 호출'했는지 생각해 볼까요? 우리가 직접 원하는 타이밍에, 원하는 인자 값을 넣어서 plus( ) 함수를 직접 호출했습니다. 너무 당연한 얘기 같겠지만, 중요한 개념입니다.
'아니, 그러면 우리가 호출 안 하는 함수도 있나? 다 우리 의도대로 호출하는 거지...'
이런 생각이 문득 들었다면, 사고 체계를 살짝 바꾸어야 합니다. 예를 한 번 들어볼까요?
1. 여러분이 병원에 가서 '홍길동 / 1995년 00월 00일'이라는 정보를 말하고 접수를 완료했습니다. 그리고 순서를 기다리다가 홍길동 씨의 차례가 돌아오면 직원이 "홍길동 환자분, 3번 진료실로 들어가실게요."라고 안내해줍니다. 이것은 위에서 언급한 plus(99, 283); 의 형태로 함수를 호출한 개념입니다. 여기서는 '홍길동'이라는 고객을 명확하게 지정하여 정해진 안내를 해주었습니다.
2. 그런데 여러분이 은행에 볼일이 있어서 갔다고 가정해 봅시다. 여러분은 은행에 들어서자마자 대기표를 뽑습니다. 제 손에 13번이라는 번호가 주어졌습니다. 그리고 기다리다가 화면에 "띵동~" 소리와 함께 13이라는 숫자가 표시되면 여러분은 직원에게 가게 됩니다. 이것은 직접 호출과는 다른 개념이죠?
우리가 설명한 2번의 케이스를 웹 사이트의 방식으로 살펴보겠습니다. 만일 [어느 웹 사이트 페이지가 로딩이 완료되면, '완료'라는 텍스트가 출력되는 팝업을 띄운다]라고 동작을 정의했다고 가정합시다.
window.onload = function(){
alert('Welcome');
};
위 코드가 <script> 태그에 작성된 html 페이지를 클릭해 열게 되면, 페이지 로딩이 완료된 순간 팝업이 출력됩니다. 여기서 window.onload라는 코드는 일종의 이벤트를 감지하는 이벤트 핸들러(Event Handler)입니다. 어떤 역할을 하냐고요? 바로 '페이지 로딩 완료라는 이벤트가 감지되면, 뭘 할지 정의'하는 기능을 합니다.
여기에 우리는 익명 함수를 이용해, ['Welcome'이라는 메시지를 출력하는 팝업을 띄워라]라고 정의를 했습니다. 우리는 여기서 해당 팝업을 직접 언제 띄우라고 정의를 한 것이 아닙니다. "로딩이 완료되면 띄워라"라고 정의를 한 것이죠. 이것이 Event Driven으로 실행되는 콜백 함수의 첫 번째 성질입니다.
Non-Blocking I/O Model
더불어 흔히 '비동기화 모델'이라고 부르는 Non-Blocking 속성에 대해서도 알아봅시다. 이번에도 Blocking 모델에 대해서 먼저 알아보도록 하겠습니다.
여러분이 집안일을 하고 있습니다. (1) 청소기를 돌리고 (2) 세탁기로 빨래를 하고 (3) 식기 세척기를 돌리고 (4) 가스 점검 날이라 직원이 방문하면 맞이 해야 합니다. 이를 Blocking 모델로 처리하면, 어떤 식으로 일을 처리하게 될까요?
간단히 말해, 청소기를 다 돌리면 세탁기를 작동합니다. 그리고 세탁기가 돌아가는 1시간 동안 가만히 기다립니다. 세탁기가 빨래를 완료되면 식기 세척기 앞으로 가서 작동합니다. 그리고 식기 세척기가 돌아가는 40분 동안 가만히 기다립니다. 이런, 식기 세척기를 돌리는 중에 초인종이 울렸네요? 가스 검침원 분이 오셨습니다. 하지만 우리는 아무것도 하지 못합니다. 식기세척기가 안 끝났거든요. 식기 세척기가 작동을 완료하면, 그때서야 가스 검침원에게 문을 열어줍니다.
조금 황당하죠? 이 예시는 말이 안 되는 상황 같지만, 프로그래밍에서는 아주 기본적인 원칙입니다. 순서대로, 완료되고 나면 다음 일을 실행한다는 원칙이죠. 이를 코드를 통해 예시로 들어보겠습니다.
var content = file.read('readme.txt');
txtPrint(content);
var result = plus(12, 510);
위 코드는 집안일 예시처럼 실행됩니다. 우선 readme.txt 파일을 읽어 들여 content 변수에 대입합니다. 그리고 txtPrint라는 함수가 content를 인자로 실행합니다. 그리고 그 실행이 끝나면 plus(12, 510) 함수를 실행해 result에 대입합니다. 한 줄, 한 줄이 작업이 완료되어야 다음 줄이 실행됩니다.
당연히 이런 작업 방식도 필요하지만, 하나를 실행하고 작업이 진행되는 동안 다른 일을 하면 안 될까요? 세탁기가 돌아가기 시작하면 식기 세척기를 돌리고, 식기 세척기가 돌아가는 동안 초인종에 가면 되니까요. 그리고 그러는 동안 세탁이 완료되면 그때 가서 빨래를 꺼내면 되는 것 아닐까요? Non-Blocking 방식은 이러한 방식을 코드로 구현한 것입니다. 예시를 들어보겠습니다.
file.read('readme.txt', function(content){
txtPrint(content);
});
var result = plus(991, 9);
위 예시가 앞서 적은 코드와 가장 큰 차이는 txtPrint(content) 함수를 실행하는 방식입니다. 물론 함수의 정의에 따라 달라지는 부분이니 상황에 따라 맞게 사용해야 하겠지만, 여기서는 readme.txt 파일을 읽기 시작하고 파일을 읽는 동안에는 plus(991,9) 함수를 실행합니다. txtPrint(content)는 언제 실행되냐고요?
[바로 readme.txt 파일 읽기 작업이 끝나는 대로]입니다. 파일을 읽는데 30분이 걸린다고 가정하면, 30분이 될 때까지는 다른 일들을 바로 시작합니다. 그러다 파일 읽기가 끝나는 순간 txtPrint(content)가 실행되는 것입니다.
여기서 설명하는 코드와 메서드 하나하나를 신경 쓰거나 이해하실 필요는 없습니다. 전혀 중요하지 않아요! 다만, 이러한 순서대로 실행한다는 것에 집중하시기 바랍니다. 세탁기 돌려놓고, 다른 집안일을 한다! 이 개념만 집중해 주세요. 여기서는 '어떤 작업이 끝나는 순간' 실행한다는 Event Driven 속성과 완료되지 않아도 다른 일을 한다는 Non-Blocking 속성이 적용되었다는 것을 이해하는 것이 중요해요.
더불어 여기서 대부분의 콜백 함수는 익명 함수로 정의되어 사용되고 있다는 점도 기억해 두시기 바랍니다.
'Programming > Javascript' 카테고리의 다른 글
7. Javascript 함수 (6) - 내부 함수 + 스코프와 클로저 맛보기 (0) | 2022.09.29 |
---|---|
7. Javascript 함수 (5) - 즉시 실행 함수란 (0) | 2022.09.27 |
7. Javascript 함수 (3) - 함수 프로퍼티 2 (0) | 2022.09.22 |
7. Javascript 함수 (3) - 함수 프로퍼티 1 (0) | 2022.09.20 |
7. Javascript 함수 (2) - 함수의 객체 특성 2 (0) | 2022.09.15 |