서버로 요청을 보내는 jQuery의 $.get() 함수를 살펴보자.

function printData() {
    var data;
    
    $.get('/domain', function(responseData) {
        data = responseData;
    });
    
    console.log(data); // undefined가 출력된다.
}

printData();

 

위의 코드에서 $.get()은 비동기 함수이기 때문에 data 변수에 어떠한 값이 담기기도 전에 반환된다. 따라서, undefined를 출력한다.

다음으로 Javascript 자체적으로 지원해주는 setTimeout() 함수도 대표적인 비동기 함수이다.

console.log("1");

setTimeout(function() {
    console.log("3");
}, 3000);

console.log("2");

 


 

내가 원하는 로직을 비동기 함수 안에 콜백 함수의 형태로 넣어주면, 실행 흐름이 완벽하게 보장된다.

비동기 함수인 ajax가 서버에서 언제 데이터를 받아오든간에 데이터를 받아온 다음에야 콜백 함수가 실행되기 때문이다.

function printData(callbackFunc) {
    $.get('/domain', function(responseData) {
        callbackFunc(responseData);
    });
}

printData(function(data) {
    console.log(data);
});

 

서버에서 받아온 데이터를 콜백 함수의 파라미터로 넘겨주며 콜백 함수를 실행하고 있다.

그런데 만약 콜백 함수로 넘어온 파라미터 값을 가공한 후에, 다시 콜백 함수로 데이터를 넘겨주고 실행하면 어떻게 될까?

function printData(callbackFunc) {
  $.get('/domain', function(responseData) {

      // 서버에서 받아온 responseData로 콜백 함수를 실행한다.
      callbackFunc(responseData, function(id) { 

          // parseData 함수가 데이터를 파싱해 id값을 추출하여, 다시 콜백 함수를 실행한다.
          auth(id, function(result) {

              // auth() 함수로 인증이 성공하면, 다시 콜백 함수를 실행한다.
              display(result, function(text) {
                  console.log(text);
              });
          });
      });
  });
}

function parseData(data, callbackFunc) {
    
    // 1. 파라미터로 넘어온 data를 파싱한다. ( 여기선 그냥 data를 넣었는데, 파싱된 데이터라 가정하자. )
    const parsingData = data;
    
    // 2. 파싱한 데이터를 콜백 함수의 파라미터로 넘겨주며 실행한다.
    callbackFunc(parsingData);
}

printData(parseData);

 

콜백 함수에서 다시 콜백 함수를 실행하고, 거기서 다시 콜백 함수를 실행한다.

이렇게 비동기 함수에서 동기성을 보장하기 위해 꼬리에 꼬리를 무는 식으로 콜백 함수를 반복 사용하는 것을 콜백 지옥이라 한다. ( Callback Hell )

 

콜백 지옥을 극복하기 위해 ES6에서 promise 문법이 추가되었고, promise를 한 번 더 보기좋게 만든게 async/await이다.