javascript가 비동기 처리를 한다?

  • 자바스크립트는 싱글 쓰레드로 이루어져 있다. 비유를 하자면 일처리를 하는 사람이 한 명 이라는 뜻이다.
    동기 처리란, 하나의 일이 끝나기 전에 다른 일을 하지 못하는 것을 말한다. 그럼 만약 자바스크립트가 동기 처리 방식으로 이루어져 있다면 어떻게 될까?
  • 예를 들어, 빨래를 하고 청소를 해야 한다고 생각해보자. 동기 처리는 빨래가 다 끝나기 전에는 청소를 할 수 없다. 따라서 총 걸리는 시간이 (빨래를 하는시간 + 청소를 하는시간)이다.
  • 하지만 비동기 처리는 하나의 일이 끝나기 전에 다른 일을 처리할 수 있는 것을 말한다. 비동기 처리는 빨래를 세탁기에 돌려놓고 빨래가 되는동안 청소를 할 수 있다. 따라서 총 걸리는 시간이 max(빨래를 하는시간, 청소를 하는시간)이다.
  • 이처럼 javascript는 효율적으로 일처리를 하기 위해 비동기 처리 방식으로 되어 있다.

그럼 동기 처리 방식이 비효율적인건가요?

  • 동기 처리 방식이 비효율적이라고 말하기는 애매하다… 위에서 예를 든 것은 어떤 일이 먼저 끝나든 상관없이 시간을 효율적으로 쓰기 위해 비동기 처리를 사용했다고 하면, 동기 처리 방식은 먼저 실행한 코드부터 결과값이 나오고 그 다음으로 넘어가기 때문에 순서대로 처리해야 하는 일에 적합하다.

비동기 처리 방식의 문제점

  • ajax라는 비동기 통신 코드를 예시로 들면 다음과 같습니다.
    function getData() {
      var data;
      $.get('https://myData.com/data/1', function(response) {
        data = response;
      });
      return data;
    }
    
    console.log(getData);
    
  • 여기서 $.get부분이 ajax통신을 하는 부분인데, https://myData.com 라는 주소로 data의 첫 번째 값을 요청(get)하는 코드이다. 정상적으로 데이터를 받았다면 response에 값이 담길 것이고 data에 할당되어 콘솔에 값이 찍힐 거라고 예상이 될 것이다.
  • 하지만 결과를 보면 콘솔에 찍히는 내용은 undefined이다. 대체 왜 그럴까?
  • 위에서 잠깐 얘기했지만 동기 처리 방식은 순서대로 실행된다는 것이 장점이다. 하지만 비동기 처리 방식은 처리가 끝나는 순서가 정해져 있지 않다. 그래서 위와 같은 문제가 생기는 것이다.
  • ajax통신은 비동기로 처리하게 되지만 그 아래 코드인 return data;는 동기처리 되기 때문에 ajax통신이 아직 끝나기 전에 실행이 되어 버린다.

콜백 함수의 사용

  • 위와 같은 문제를 해결하기 위해 콜백함수(callback function)을 사용하기 시작했다.
    function getData(callback) {
      $.get('https://myData.com/data/1', function(response) {
        callback(response);
      });
    }
    getData(function(data) {
      console.log(data);
    });
    
  • 위 코드와 같이 콜백함수를 사용하면 비동기함수가 실행되고 난 후에 콜백함수를 실행하여 원하는 결과값을 얻을 수 있다.

콜백 지옥(callback hell)

  • 우리가 웹 서비를 만들다 콜백함수의 콜백함수를 만들고 또 콜백함수를 만들고 또… 다음 코드와 같은 콜백 지옥(callback hell)이 생길 수 있다.
    $.get(url, function(response) {
      callback1(response, function(result1) {
        callback2(response, function(result2) {
          callback3(response, function(result3) {
            ...
          })
        })
      });
    });
    
  • 이를 해결하기 위해 다음과 같이 함수 선언을 하여 코드를 분리하였다.
    $.get(url, function(response) {
      callback1(response)
    }
    function callback1(response) {
      callback2(response)
    }
    function callback2(response) {
      callback3(response)
    }
    function callback3(response) {
      ...
    }
    
  • 위와 같이코드를 분리하여 해결할 수 있지만 promise라는 객체를 사용하여 구현할 수도 있다.

promise

  • promise는 javascript의 비동기 처리에 사용되는 객체로, 기대한 값을 얻은 경우(resolved)와 얻지 못한 경우(rejected) 두 가지 정보를 얻을 수 있다.
  • 콜백 함수의 사용에서 보았던 예시코드에 promise를 적용하면 다음과 같다.
    function getData() {
      return new Promise(function(resolve, reject) {
        $.get('https://myData.com/data/1', function(response) {
          resolve(response);
        });
      })
    }
    getData().then(function(data) {
      console.log(data)
    });
    

promise의 동작 방식

  • Promise는 비동기 함수로부터 동기적으로 반환되는 객체이다. Promise는 다음 3가지 상태 중 하나를 가진다.
    • Pending: 아직 fulfilled 또는 rejected 상태가 아님(대기상태)
    • Fulfilled: onFulfilled()가 호출된다 (ex) resolve() 호출)
    • Rejected: onRejected()가 호출된다 (ex) reject() 호출)

Pending(대기 상태)

  • new Promise() 메서드를 호출하면 Pending(대기) 상태가 된다.
    new Promise();
    
  • new Promise() 메서드를 호출할 때 콜백 함수의 인자로 resolve, reject을 사용할 수 있다.
    new Promise(function (resolve, reject) {
      // ...
    });
    

Fulfilled(이행 상태)

  • 다음과 같이 resolve를 실행하면 Fulfilled 상태가 된다고 말한다.
    new Promise(function (resolve, reject) {
      resolve();
    });
    
  • resolve함수를 호출한 리턴값을 then에서 받아 사용할 수 있다.

Rejected(거절 상태)

  • 다음과 같이 reject를 실행하면 Rejected 상태가 된다고 말한다.
    new Promise(function (resolve, reject) {
      reject();
    });
    
  • reject함수를 호출하여 리턴된 에러를 catch에서 받아 사용할 수 있다.
  • Fulfilled 또는 Rejected상태가 되면 settled 상태가 되었다고 말한다. 그리고 한번 settled 상태가 되고 나면, Promise는 다시 settled 될 수 없다. 즉, 한 번 resolve() 또는 reject()을 호출했으면 그 이후에 다시 resolve() 또는 reject()을 호출했을 때 아무런 효과가 없다.