ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript의 비동기처리에 대해
    Web 2023. 8. 13. 15:29

    배경

    기본적인 비동기처리, 콜백함수, promise객체, async/await의 개념에 대해서는 알고 있었다.

    하지만 회사에서 일을 할때 비동기 처리에 관한 지식부족으로 인해 다음과 같은 문제가 발생하였다.

    • 비동기처리를 하지않아 undefined로 인한 에러가 발생,
    • 내가 작성한 코드 await을 사수님이 Promise.all로 리팩토링 하시는 과정에 대한 이해부족.

     

    위 두가지는 내가 실무에서 비동기처리에 대한 지식부족으로 생겼던 대표적인 문제들이다.

    이제 자바스크립트의 비동기처리에 대한 내용을 정리하겠다.

     

     

     

    동기(Synchronous)란?

    코드가 순차적으로 실행되는 것을 동기(Synchronous)라고 한다. 기본적으로 자바스크립트 언어 자체는 싱글 쓰레드 언어이므로, 한 번에 하나의 작업만 실행할 수 있다. 따라서 다른 작업이 수행되는 동안 작업을 잠시 중단하고, 작업이 끝난 후 예정된 작업을 실행할 수 있다.

    • 직관적으로 이해하기 쉽다.
    • 네트워크통신 등의 시간이 오래 걸리는 작업을 실행하게 되면, 그 작업을 기다린 후에 다른 작업을 실행하므로 성능이 크게 안좋아진다.

     

    비동기 (Asynchronous)란?

    비동기(Asynchronous)란, 두 개 이상의 작업이 동시에 진행되는 것을 의미한다. 

    메인 쓰레드가 작업을 다른곳으로 인가하여 처리하고 작업이 완료되면 콜백함수를 받아 실행한다. 

    (참고로, 자바스크립트의 call stack은 싱글 쓰레드이지만 Web APIs(setTimeout, 네트워크통신)은 멀티 쓰레드이기 때문에 동시에 병렬적으로 작업 수행이 가능하다)

    • 이해가 조금 어렵다.
    • 병렬적으로 작업 처리가 가능하므로, 코드 실행시간이 줄어들어 성능이 크게 개선된다.
    • 대표적으로 setTimeout(), fetch()등의 네트워크 통신할 때 주로 사용한다.

     

    예를들어, setTimeout()함수에서 실행되는 로직이 있다고하자.

    1. setTimeout()함수의 시간을 기다리지 않고 다음 줄의 코드를 실행한다.
    2. setTimeout()에서 지정한 시간이 되면, 내부 로직을 실행한다.

    따라서 병렬적인 작업 수행이 가능하다.

     

     

     

    동기(Synchronous)와 비동기(Asynchronous) 비교

    동기와 비동기

    동기(Synchronous)는 작업수행이 끝나면 다른 작업이 실행된다. 따라서 전체 코드 수행시간의 합이 일을 처리하는데 사용한 시간이다. 위 그림에서는 각각의 task들의 합인 45초가 걸린다.

    비동기(Asynchronous)는 작업이 실행될 때 병렬적으로 다른 작업을 수행할 수 있다. 따라서 일을 처리하는데 사용하는 시간은 가장 실행시간이 긴 task의 시간과 같다. 위 그림에서는 20초가 걸린다.

     

     

    비동기 처리의 문제

    동기(Synchronous)처리에 비해 수행 시간을 월등하게 개선한 비동기(Asynchronous)처리 방식에도 문제가 있을까?

    비동기(Asynchronous)처리 방식에도 문제가 존재한다.

    비동기(Asynchronous)함수 내부의 데이터의 값을 외부에서 사용하거나, 가공할려고 할 때 문제가 발생할 수 있다. 비동기함수에서 아직 작업이 진행중인데 대기하지 않고, 바로 다음코드에서 그 데이터 값을 사용하면 아직 데이터가 없기 때문에 문제가 발생한다. 

     

    아래 예시와 같은 문제가 생길 수 있다.

    function testData() {
      let data;
    
      setTimeout(() => {
        data = 2;
      }, 2000);
    
      return data;
    }
    
    function getData() {
      let totalData = testData();
      totalData++;
      console.log(totalData);
    }
    
    getData();

     

     

    testData() 함수는 setTimeout을 사용하여 비동기적으로 처리되고, 2초 후에 data가 2로 설정된다. getData() 함수는 testData()를 호출하고 바로 다음줄에 totalData를 증가시키기 때문에 testData() 함수의 비동기 작업이 완료되기 전에 totalData값이 증가된다. 비동기 작업이 완료되기 전 testData()가 반환하는 값은 undefined이기 때문에 undefined + 1 = NaN이 출력된다.

     

     

    따라서 비동기처리를 할 때 작업의 순서를 맞추는것이 필수적인 경우가 있는데, 이를 해결하는 방법이 바로 콜백함수이다.

     


    콜백함수의 비동거 처리

     

    먼저 콜백함수는 자바스크립트를 공부하면 수없이 들어봤을 개념이다. 그래서 콜백함수가 뭔데?

    콜백함수란 함수의 매개변수에 함수를 넘겨 함수 내에서 매개변수 함수를 실행시키는 기법이다. 쉽게 말하면, 다른 함수에게 매개변수로 전달되어 실행이 필요한 시점에 호출되는 함수이다. 

     

    콜백함수의 개념은 알겠다. 그러면 콜백함수와 비동기처리가 무슨 관계인가?

    비동기 방식은 요청과 응답의 순서를 보장하지 않는다. 따라서 코드가 다른 작업이 완료되기를 기다리지 않고 다른 작업을 동시에 수행하게 된다. 이때 비동기처리의 결과에 의존적인 코드를 콜백함수를 통해 순서를 보장할 수 있다. 

     

    예를 들어, 웹 브라우저에서 네트워크 요청을 보낼 때 비동기 방식으로 요청을 보내게 된다. 따라서 네트워크 요청을 보낸 후에도 다른 작업을 계속 수행할 수 있고, 요청이 완료될 때 미리 정의한 콜백 함수가 호출되어 결과를 처리할 수 있다. 

     

     

    위 예시의 문제도 콜백함수로 쉽게 해결할 수 있다. 

    function testData(callback) {
      let data
      setTimeout(() => {
        data = 2;
        callback(data);
      }, 2000);
    }
    
    function getData() {
      testData((data) => {
        let totalData = data;
        totalData++;
        console.log(totalData);
      });
    }
    
    getData();

    이 코드에서 setTimeout내부에서 data값을 2로 설정하고, 설정한 후에 callback(data)을 호출하여 데이터를 전달한다. 이렇게 하면 getData() 함수 내에서 비동기 작업이 완료된 후에 결과가 올바르게 처리되고 출력된다. 

     

     

    위 코드를 Arrow function을 이용하면 조금 더 간결하게 작성할 수 있다. 이 방법이 실무에서도 더 자주 쓰이는 방법이다.

    const testData = (callback) => {
      setTimeout(() => {
        const data = 2;
        callback(data);
      }, 2000);
    };
    
    const getData = () => {
      testData((data) => {
        let totalData = data;
        totalData++;
        console.log(totalData);
      });
    };
    
    getData();

     

    이런 콜백함수도 문제점이 존재한다.

    콜백함수의 남용은 코드의 복잡도를 증가시키고 개발자가 코드의 흐름을 이해하기 어려워질 수 있어 흔히 말하는 '콜백지옥'에 빠질 수 있다. 이 콜백지옥 문제를 해결하기 위해 Promise객체를 사용할 수 있다. Promise객체에 대한 내용은 다음에 포스팅하도록 하겠다. 

     

     

     

     

     

     

    참고

    https://jindev-t.tistory.com/90

    https://inpa.tistory.com/entry/%F0%9F%8C%90-js-async

Designed by Tistory.