Callback 함수 비동기 호출
Callback 함수는 다른 함수의 파라미터로 전달하는 함수를 말한다. 인자로 전달된 함수는 동기적으로 실행하거나 비동기적으로 실행할 수 있다.
callback 함수를 비동기적으로 처리하기위해서는 특정 액션이 취해질 때 callback 함수를 호출하게 된다.
callback in Action :
반복 실행함수는 callback in action에 속한다.
['a','b','c'].map((item)=>item+item);
이벤트 핸들러 또한 callback in action에 속한다. 특정 이벤트가 터졌을 때 callback 함수를 호출하게 되면서 실행시간을 임의로 조정할 수 있다.
const btn = document.querySelector('button')
btn.addEventListener('click', ()=>{
console.log("Button is clicked");
})
Blocking vs Non-Blocking
동기화 프로그래밍과 비동기 프로그래밍의 차이는 blocking과 non-block으로 간단하게 이해할 수 있다. Javascript 엔진은 한 번에 한개의 Task만 실행할 수 있는 싱글 스레드(Single Thread) 방식으로 동작하기 때문에 실행 컨텍스트에 올라간 함수의 실행시간이 오래 걸린다면 Blocking이 발생한다.
Javascript 엔진은 단 하나의 실행 컨텍스트 스택만 가지고 있기 때문에 동시에 2개 이상의 함수를 호출할 수 없다. Blocking 상태를 벗어나기 위해서 멀티 스레드를 돌리기 위해서는 비동기 프로그램이 필요하다.
동기화 프로그래밍
먼저 동기화 프로그래밍은 전화와 동일한 로직을 가지고 있다. 전화벨이 울리면 내가 하고 있던 일이 있더라도 잠깐 멈추고 전화를 받는다. (Blocking)
또한 전화를 받자마자 상대방과의 커뮤니케이션이 바로 시작된다. 이것이 동기화 프로그래밍이다. 현재 진행중인 로직을 멈추고, 요청에 대한 결과가 동시에 발생하는 것이다. (Synchronous)
비동기 프로그래밍
반대로 비동기 프로그래밍은 카카오톡을 주고 받는 것과 같다. 톡 알람이 울려도 현재 내가 하고 있는 일을 멈출 필요는 없다. 계속 나의 일을 하다가 시간이 나면 톡을 확인하면 된다. (Non-Blocking)
또한 톡 알람이 울린다 하더라도 상대방과의 커뮤니케이션이 바로 이어지는 것이 아니다. 나중에 내가 시간이 날 때(Event 발생) 톡을 확인하면서 대화가 이어진다. (Asynchronous)
비동기 프로그래밍
DOM Element의 이벤트 핸들러는 비동기 프로그래밍으로 작동한다. 마우스, 키보드의 이벤트를 받거나 페이지가 로딩되는 이벤트가 발생되었을 때 Callback 함수가 실행된다.
타이머 API나 애니메이션 API(requestAnimationFrame) 등의 타이머들은 비동기 프로그램으로 작동한다.
가장 일반적인 비동기 프로그램이 서버에 자원을 요청하는 fetch API나 AJAX(XHR)다. 서버에 특정 자원을 요청할 때 비동기식으로 요청을 던지게 되고 응답을 받은 후 나머지 로직을 처리하게 된다. 서버에 요청 후 응답이 지연되는 경우 Blocking이 일어나면 안되기 때문에 비동기식으로 처리하게 된다.
이벤트 루프
Javascript 비동기 프로그래밍
동기식 프로그래밍은 클라이언트는 서버에 자원을 요청하고 응답을 받을 때 까지 아무런 일도 하지 않고 응답만 기다린다. 반명 비동기식 프로그래밍은 서버에 요청 후 응답을 기다리는 시간 동안 다른 일을 처리할 수 있다.
그럼 Javascript 코드 내에서 비동기 프로그램을 어떻게 구현할 수 있을까? 비동기식 프로그래밍을 구현하기 위해서 가장 많이 사용하는 방법이 Callback 함수를 사용하는 것이다.
Callback() 은 부재 중 전화가 왔을 때 다시 연락을 달라는 의미다. 비동기식 프로그래밍의 순서를 제어하기 위한 용도로 사용된다.
아래 소스코드를 실행하면 랜덤하게 지연 시간이 주어지지만 콜백함수 1, 2, 3의 실행 순서를 일정하게 제어할 수 있다.
const printString = function(string, cb){
setTimeout(function(){
console.log(string);
cb();
},
Math.floor(Math.random() * 100 + 1)
}
const printAll() = function(){
printString("Callback 1" , ()=>{
printString("Callback 2" , ()=>{
printString("Callback 3" , ()=>{
}
}
}
}
Callback 함수를 사용해서 Error 핸들링을 할 수 있다. Error가 발생한 경우 Callback 함수의 인자값을 변경하면서 프로그래밍 로직 내 발생하는 Error에 대한 적절한 대응이 가능하다.
const errorHandler = function(callback){
if(정상적인 로직){
callback(null, data):
}
if(비정상적인 로직){
callback(data, null);
}
}
function callback(err, data){
if(err){
console.log("Error Occured!");
return ;
}
return data;
}
Callback Hell
Callback 함수를 사용하면 비동기 프로그래밍의 순서를 수월하게 제어할 수 있지만, 함수의 차원이 깊어지면 코드의 가독성이 저해된다. 무수히 많이 이어지는 Callback 함수의 향연을 Callbak Hell 이라고 한다.
만약 위의 예제 코드에서 콜백함수가 10개 혹은 100개라고 했을 때 정상적인 프로그래밍 로직이라고 볼 수 없을 것이다.
const printString = function(string, cb){
setTimeout(function(){
console.log(string);
cb();
},
Math.floor(Math.random() * 100 + 1)
}
const printAll() = function(){
printString("Callback 1" , ()=>{
printString("Callback 2" , ()=>{
printString("Callback 3" , ()=>{
printString("Callback 1" , ()=>{
printString("Callback 2" , ()=>{
printString("Callback 3" , ()=>{
printString("Callback 1" , ()=>{
printString("Callback 2" , ()=>{
printString("Callback 3" , ()=>{
printString("Callback 1" , ()=>{
printString("Callback 2" , ()=>{
printString("Callback 3" , ()=>{
}
}
}
}
}
}
}
}
}
}
}
}
}
Callback 함수를 리턴하고 다시 나와도 현재 어떤 로직을 처리하는지 코드를 보고 바로 이해하기 힘든 경우인데, 이 Callback Hell을 제거하기 위해서 나오는 비동기 프로그래밍의 도구가 Promise다.
'Programming' 카테고리의 다른 글
[Javascript] Promise란 무엇인가? ( async await 사용 방법) (0) | 2022.05.18 |
---|---|
[Javascript] 이벤트 루프 Event Loop VS Task Queue란? (0) | 2022.05.18 |
[Javascript] 명령형 vs 선언형 프로그래밍 (0) | 2022.05.17 |
[Javascript] Underbar 구현 (0) | 2022.05.17 |
[Javascript] Function arguments 속성이란? (0) | 2022.05.17 |
댓글