본문 바로가기
Woowa Techcourse/Missions

Javascript 콜백 함수(Callback Function)

by mingule 2021. 4. 12.

[ 용어 정리 ] 

동기(Synchronous)

  - real-time communication where each party receives messages instantly.

  - 요청과 그 응답이 즉시 이루어지는 것

  - 뭔가 헷갈리는 말인 것 같은데, 어떤 A(요청) - A(응답) - B(요청) - B(응답) - C(요청) - C(응답) 이렇게 요청과 응답이 일렬로 이루어지고 이루어짐과 동시에 즉시 다음 요청이 실행되고 .. 이렇게 이해하면 조금 덜 헷갈리는 것 같다.

 

비동기(Asynchronous)

  - two or more objects or events not existing or happening at the same time.

  - 2개 이상의 요청과 그 응답이 같은 시간에 이루어질 수 있는 것

  - 이것도 마찬가지로, 동기의 반대로 생각해보면 조금 덜 헷갈린다. A(요청) -- B(요청) -- C(요청) -- B(응답) -- C(응답) -- A(응답) 응답이 즉시 오는 게 아니라 중간 중간 다른 애들이 껴서 실행되고 응답이 오고 등등을 할 수 있는 상태라고 생각하면 조금 쉽다.

 

콜백함수(Callback function)

  - function passed into another function as an argument

  - 어떤 함수의 인자로 들어가는 함수


Javascript는 동기적으로 동작하기 때문에, 시간이 오래 걸리는 무언가를 실행시키고 나면 다른 동작들은 모두 멈춰있게 된다. 그렇기에 시간이 오래 걸리는 무언가를 하지 않는다면 큰 문제가 생기지 않지만, 만약 시간이 오래 걸리는 무언가를 실행시킨다면 사용자는 빈 화면만을 바라보게 된다. 이런 문제를 해결하기 위해, 우리는 비동기 방식을 활용한다.

 

비동기 방식은 동기적 방식과는 반대되는 개념으로, 요청을 보내고 응답을 기다리는 동안 그저 기다리기만 하는 것이 아니라, 다른 일들을 병렬적으로 처리할 수 있게 하는 방식을 뜻한다. 

 

코드를 아래와 같이 한 번 작성해 보았다. 

function notCallback(id) {
  setTimeout(() => {
    console.log("1초 기다릴게요");
    const user = {
      id: `${id} 아이디 입니다.`,
    };

    return user;
  }, 1000);
}

const user = notCallback(1);
console.log("user:", user);

 

뭔가 생각대로라면 마지막 console에 의해 user:  {id : "1 아이디 입니다"}가 튀어나와야 할 것 같은데 그렇지 못하다.

그 이유를 함수가 실행되는 순서에 맞추어 한번 적어보겠다.

 

callback(1)이 호출 Stack에 올라 실행된다.

setTimeout()이 Task Queue에 쌓인다. (setTimeout은 비동기 함수기 때문에 다음 줄로 넘어가버림)

console.log('user:' user)가 호출 Stack에 올라 실행된다. → user : undefined

setTimeout()이 실행된다. → 1초 기다림

 

이 내용을 조금 더 잘 이해하려면 Event Loop에 대해 알아야하는데, Event Loop은 다음 포스트에 작성해보겠다. (이벤트루프 넘 어려웡)

 

이런 문제를 해결하려면, 아래와 같이 Callback 함수를 사용하면 된다. 

function getUser(id, callback) {
  setTimeout(() => {
    console.log("1초 기다릴게요");
    const user = {
      id: `${id} 아이디 입니다.`,
    };

    callback(user);
  }, 1000);
}

getUser(1, (user) => {
  console.log("user:", user);
});

위에 작성된 getUser의 2번째 parameter로 들어가는 함수가 callback 함수다. 

 

getUser가 호출되면서 (user) => {console.log('user:', user} 이라는 함수가 callback 인자로 넘어가게 되고, 

이번에는 호출 Stack에 아무것도 없는 채로 setTimeout이 Task Queue에 쌓이게 된다ㅏ.

그렇게 쌓인 Task Queue는 1초가 지난 후, "1초 기다릴게요", "user: {id: "1 아이디 입니다."}"를 순차적으로 반환하게 된다.

 

 

 

setTimeout 안에 함수를 전달해서 호출하면서 우리가 이전에 마주했던 문제를 해결한 것이다. 

 

그런데 만약, 이런 함수를 여러개 중첩해서 사용한다고 했을 때에는 문제가 발생하게 된다. 함수 안에 함수, 또 그 안에 함수, 함수 . . . 이렇게 되어버려서 아래와 같이 가독성이 핵 떨어지는 코드를 만들 수가 있다. 저런.. 이런 코드를 콜백 지옥(Callback Hell)이라고 한다.

콜백 지옥 짤 / 출처 : google

그럼 요런 문제는 어떻게 해결해야 할까?!

이런 콜백 지옥을 해결하기 위해 Promise, Async/Await이 나왔다. 만쉐이~

Promise와 Async/ Await도 다음 포스트에 이어 작성하도록 하겠따 . ㅎㅎ헤헤헤

댓글