본문 바로가기

JavaScript

[JavaScript] 비동기 처리 (1)

리액트 프로젝트를 진행하면서 API 서버를 연동할 때 API 요청에 대한 상태를 잘 관리해주어야 하는데, 예를 들어 요청이 시작되었다면 로딩 중, 요청이 성공하거나 실패했을 때는 로딩이 끝났음을 알려주어야 합니다. 또한, 요청이 성공했다면 서버에서 받아 온 Response에 대한 상태를 관리하고, 요청이 실패했다면 서버에서 받아 온 Error에 대한 상태를 관리해야 합니다. 

 

리덕스를 사용하면서 위와 같은 비동기 작업을 관리해야 한다면, 리덕스 미들웨어를 사용하면 효율적이라고 하는데, 과연 효율적이라는 것을 느낄 수 있을 정도로 비동기 처리에 대한 이해가 충분한가에 대한 의심이 들어 다시 기초로 돌아와 비동기 처리에 대한 글을 정리해보려고 합니다.

비동기 처리

자바스크립트의 싱글 스레드, 콜스택 과 같은 특징을 통해 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 순차적으로 다음 코드를 먼저 실행하는 것을 말합니다.

비동기 처리의 예

웹 애플리케이션을 만들다 보면 처리할 때 시간이 걸리는 작업이 있습니다. 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호출하여 데이터를 수신하는 작업을 할 경우, 네트워크 송수신 과정에서 시간이 걸리기 때문에 즉시 처리되지 못하고 응답을 받을 때까지 기다렸다가 전달받은 응답 데이터를 처리합니다.

 

만약 이를 동기적으로 처리한다면, 네트워크 송수신 과정에서 걸리는 시간 동안 다른 작업은 모두 중지 상태가 되기 때문에 그 시간이 길어진다면, 웹 애플리케이션을 사용하는 유저의 이탈을 야기할 수 있을 것입니다.

 

서버 API를 호출하는 것 외에도 작업을 비동기적으로 처리할 수 있는 setTimeout 함수를 사용하여 간단히 특정 작업을 예약할 수 있습니다. 아래 코드의 출력을 살펴보도록 하겠습니다.

 

function printData() {
  var data;
  setTimeout(() => {
    data = 3;
    console.log("1번째 출력:" + data);
  }, 1000);
  console.log("2번째 출력:" + data);
}

printData();
2번째 출력:undefined
1번째 출력:3

 

printData 함수가 호출되면, data 변수가 선언이 됩니다. 그 다음 setTimeout 함수가 호출이 되는데 1초 후에 콜백 함수를 실행하도록 설정해두었습니다.

 

출력을 보면, 1초 후에 콜백함수를 실행하도록 선언해두었다고 해서 1초 동안 동작을 멈춘 것이 아니라, 그다음 줄인 2번째 출력을 먼저 실행하게 됩니다.

 

또한, data 변수는 선언이 된 것이지, 할당은 setTimeout의 콜백함수에서 해주고 있기 때문에 먼저 출력된 2번째 출력의 data값은 undefined이 됩니다.

콜백 함수와 콜백 지옥

콜백 함수란, 위에서 보았듯이 setTimeout에 의해 1초 후에 실행될 함수를 말합니다. 1초 후라는 것은 서버 응답을 받을 때까지의 시간으로 생각할 수도 있겠습니다. 

 

다른 코드를 보도록 하겠습니다. 파라미터 count라는 값을 받아 1초 후에 10을 더해 return 해주는 함수입니다.

 

function increase(count, callback) {
  setTimeout(() => {
    const result = count + 10;
    if (callback) {
      callback(result);
    }
  }, 1000);
}

increase(0, (result) => {
  console.log(result);
});
10

 

이 함수를 통해서 1초씩 총 5초동안 10, 20, 30, 40, 50이라는 값을 출력하게끔 처리하고 싶다면 콜백 함수를 중첩하여 구현할 수 있습니다.

 

function increase(count, callback) {
  setTimeout(() => {
    const result = count + 10;
    if (callback) {
      callback(result);
    }
  }, 1000);
}

increase(0, (result) => {
  console.log(result);
  increase(result, (result) => {
    console.log(result);
    increase(result, (result) => {
      console.log(result);
      increase(result, (result) => {
        console.log(result);
        increase(result, (result) => {
          console.log(result);
        });
      });
    });
  });
});
10
20
30
40
50

 

아래와 같이 결과가 잘 나오는 것을 확인할 수 있습니다. 아직까지는 그럭저럭 괜찮아 보입니다. 그럼 위와 같은 방법으로 200까지 출력해야 한다면.. 코드는 마치 피라미드와 같은 형태로 짜여서 가독성이 매우 좋지 않은 코드가 형성될 것입니다.

 

바로 이런 형태를 '콜백 지옥' 이라 합니다. 코드 실행의 문제는 없지만, 지양해야 할 형태의 코드인 것 같다는 건 분명합니다. 그렇다면, 이를 어떻게 해결했을지 다음 글에서 이어가도록 하겠습니다.