💡 Oh My Legacy 시리즈는?
OML에서, 레거시 코드는 다른 사람으로부터 상속받은 코드라는 의미로 쓰입니다.
실무를 경험하면서 만났던 레거시 코드에 대해 분석했던 경험을 회고하며 QnA를 작성한 시리즈이며, 회고이기에 실제 코드와 유사성이 있지만 동일하지는 않습니다.
실무에서 API를 처음으로 붙여볼 때, API 통신을 위해 규칙적으로 쓰이는 함수가 있을거라 생각했습니다. 그리고 역시나 Ajax를 통해 API를 호출하는 공통 함수를 발견했죠!
//공통함수
callAjax(url, params, type, successCallback, failCallback){
$.ajax({
url:url,
type:type,
data:JSON.stringify(params),
success: successCallback, // success를 콜백함수를 받는다.
fail : failCallback //fail도 콜백함수를 받는다.
}
});
}
이 공통 함수를 사용한다면 아래와 같이 API를 호출할 수 있을겁니다.
//공통함수를 사용하는 페이지 : 데이터를 보내서 todo에 추가한다.
callAjax('/todos', data, 'POST', successInsertTodo, failInsertTodo)
function successInsertTodo(response){...}
function failInsertTodo(error){...}
여기서 ajax에 대한 응답 처리는 함수(successCallback, failCallback)로만 할 수 있습니다.
이렇게 다른 함수에 인자로 넘겨지는 함수를 콜백함수라고 합니다.
만약 응답 처리를 return response
와 같은 함수가 아닌 값으로 하면 어떻게 될까요?
왜 비동기 통신의 결과는 콜백함수로 처리해야 할까요?
비동기와 이벤트 루프에 대해 알면 이 질문에 대한 답을 알 수 있습니다!
asynchronous의 접두사 a는 not을 의미합니다.
그렇다면 우선 synchronous, 동기 프로그래밍에 대해 알아봅시다.
동기 프로그래밍(synchronous programming model)는 하나의 작업을 시작하면 끝이 나야 그 다음 작업을 시작할 수 있습니다. 멀티 스레드, 멀티 프로세서를 사용한다고 해도 병렬적으로 이루어질 뿐 지금 작업이 완료 되어야 다음 작업을 진행할 수 있습니다.
사실 동기 프로그래밍에서 작업이 짧다면 문제가 없습니다. 오히려 실행 순서를 보장해주니 편할 수도 있습니다.
예를 들어, 동기 프로그래밍으로 작업이 이루어지는 두 개의 스레드가 있다고 칩시다. 클릭을 한 번해서 0.0001초 동안 이루어져야하는 작업이 있고, 우리는 두 번 클릭을 했습니다. 클릭 당 하나씩 스레드를 차지한다면? 우리는 0.0001초 후에 다음 작업을 실행하면 됩니다. 0.0001초를 감지할 사람은 없으니 문제가 없겠죠. 그런데, 이 클릭 한 번에 이루어지는 작업이 1분 이상이 된다면요? 1분이 지날 때까지 어떤 작업도 할 수 없다면요?
비동기 프로그래밍(asynchronous programming)은 이런 오래 실행해야하는 작업을 시작하고, 해당 작업이 완료될 때까지 기다리지 않고 바로 다른 작업을 실행할 수 있도록 하는 기술입니다. 비동기 프로그래밍으로 위에서 언급한 예시 작업이 이루어진다면, 클릭 후 1분을 기다리지 않고 다른 작업을 하다가 1분 후에 값이 돌아오게 됩니다.
자바스크립트는 동기, 비동기를 모두 사용합니다.
자바스크립트에서 Event handler, XMLHTTPRequest(HTTP 요청), setTime과 같은 비동기 함수들이 있고, 이 함수들이 호출되면 비동기로 작업을 처리합니다.
그렇다면 자바스크립트가 실행될 때, 어떻게 비동기 처리를 하는 걸까요?
자바스크립트 엔진은 힙, 스택, 큐로 구성이 되어 있습니다.
1) 힙 : 메모리 영역을 지칭합니다.
2) 스택 : 함수를 호출하면 스택으로 쌓이게 됩니다(실행 컨텍스트)
3) 큐 : 처리할 메시지의 대기열 입니다.
자바스크립트 엔진에서 비동기 작업을 해야하는 함수가 호출 되는 경우,
1. 작업을 큐로 보냅니다.
2. 큐로 보내진 후 작업이 완료가 되고, 스택이 비면
3. 이벤트 루프는 3)큐 대기열에서 가장 오래된 메시지부터 큐에서 꺼내 처리하기 시작합니다.즉, 작업을 다시 스택으로 보내게 됩니다.
기억해야할 건, 스택은 함수를 호출합니다.
이 부분에서 Q.callAjax는 왜 successCallback이 필요했을까?에 대한 답을 할 수 있습니다.
callback 함수를 호출하지 않고선, response 값을 처리할 수 없게 되는 것입니다.
https://eloquentjavascript.net/11_async.html
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Asynchronous/Introducing
https://html.spec.whatwg.org/multipage/webappapis.html#task-queue