Front-end/JS

자바스크립트 콜백 함수와 비동기 처리 Call back func & Asynchronous

ciocio 2021. 9. 20. 23:30

콜백 함수를 이해하기 위해서는 자바스크립트가 자료를 어떻게 비동기적으로 받아오는 지, 해당 원리를 이해할 필요가 있다.

 

2021.09.18 - [개발 공부/Browser] - Event Loop & Task queue 이벤트 루프와 태스크 큐

 

Event Loop & Task queue 이벤트 루프와 태스크 큐

📌 브라우저 환경 📍 자바스크립트 엔진 (싱글 스레드) 대부분의 자바스크립트 엔진은 크게 2가지 영역으로 구분할 수 있다. ✔ 콜 스택 call stack (실행 컨텍스트 스택) 소스코드 평가 과정에서

code-designer.tistory.com

 

 

📌  비동기 함수에 콜백 함수가 필요했던 이유

 

// 여기서 흔히 말하는 callback 함수는 successCallback & failureCallback 😉
const get = (url, successCallback, failureCallback) => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();
 
  // onload는 이벤트 핸들러에 바인딩되는 비동기 함수
  xhr.onload = () => {
    if(xhr.status === 200) {
      // 비동기 함수의 처리 결과를 조작
      successCallback(JSON.parse(xhr.response));
    }
    else{
      // 비동기 함수의 처리 결과를 조작
      failureCallback(xhr.status);
    }
  };
};

get('https://code-designer.tistory.com/post/1', console.log, console.error);

 

비동기 함수란?
함수 내부에 비동기로 동작하는 코드를 포함한 함수

 

콜백 함수??
사실 콜백 함수가 단어적으로 특별한 함수가 아니다. 우리가 알고있는 '함수'와 같은데, 비동기 처리의 결과를 제어하기 위해 다시 호출된다 (call back) 는 점에서 '콜백 함수'라고 부르는거다.
"비동기 처리 결과를 제어하기 위해"라는 콜백 함수의 목적을 잃지 말자. 

 

(일반 함수가 아닌) 비동기 함수를 호출하면,

함수 내부의 코드가 완료되지 않았다 해도 (평가 -> 실행 -> 종료 단계를 거쳐) 즉시 종료된다. 

즉, 비동기 함수 내부에서 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다.

 

 

ex.

setTimeout 함수는 setTimeout 함수의 콜백 함수가 비동기로 동작하기 때문에 비동기 함수이다.

setTimeout 함수를 호출하면,

(✔  콜백 함수 호출 스케줄링, ✔  타이머 id 반환 후) 즉시 종료된다.

즉, setTimeout 함수의 콜백 함수(비동기 함수)는 setTimeout 함수가 종료된 이후에 호출된다.

 

 

-->  setTimeout 함수's 콜백 함수의 상위 스코프가 없음 !!
-->  caller가 없기때문에 콜백 함수의 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당할 수 없다.
-->  따라서 비동기 함수의 처리 결과에 대한 후속 처리는 비동기 함수 내부에서 진행해야 한다.
-->  이 후속처리를 위해 비동기 함수에 콜백 함수를 전달하는 거다 !!

 

 

📌  콜백 패턴을 지양해야하는 이유

 

get('/step1', a => {
  get('/step2/{a}', b => {
    get('/step3/{b}', c => {
      get('/step4/{c}', d => {
        console.log(d);
      });
    });
  });
});

 

전달되는 콜백함수가 있어야 비동기 함수의 처리 결과를 조작할 수 있기 때문에

자칫하면 위와 같은 뫼비우스의 띠가 나타난다 ...

이런 방식은 가독성도 안좋지만 무엇보다 유지 보수를 힘들게 한다.

 

try {
  setTimeout(() => {throw new Error('Error!');}, 1000);
} catch (e) {
  console.log('에러 캐치', e);
}

 

try ... catch ... finally 문 ?
에러 처리를 구현하는 문이다.
try 코드 블록에 포함된 문 중에서 에러가 발생하면 해당 에러는 catch문의 err 변수에 전달되고 catch 코드 블록이 실행된다.
finally 코드 블록은 에러 발생과 상관없이 반드시 1번 실행된다.

 

콜백 패턴은 에러 처리면에서도 심각한 문제점을 가지고 있다. 

위 코드를 살펴보면, setTimeout 함수는 콜백 함수를 브라우저에 넘기고 먼저 종료된다.

이미 자바스크립트 엔진의 실행 컨텍스트 스택에서 제거가 된 것이다. setTimeout 콜백 함수는 caller가 존재하지 않음을 뜻한다.

 

에러는 호출자 caller 방향으로 전파된다. 콜 스택의 아래 방향 ( 실행중인 컨텍스트의 하위 컨텍스트 ) 으로 전파된다.

setTimeout 함수의 콜백 함수를 호출한 건 setTimeout 함수가 아니기 때문에,

catch 블록은 콜백 함수의 에러를 캐치하지 못한다. ( 참고로 setTimeout 함수는 타이머 id를 반환한다. 에러와 전혀 상관없음 )

반응형