비실이의 개발 성장기

javascript async & await 알아보기 본문

프론트엔드/javascript

javascript async & await 알아보기

DubbingLee 2020. 5. 30. 14:35

# async & await 이전의 비동기 코드 개발

  • javascript 에서 비동기 연산의 결과를 보장받기 위해 콜백 또는 Promise chain 방식을 사용합니다. 
  • 하지만, 위 두가지 방식으로 코드를 짜고 나면 코드구조가 복잡해져 있는 것을 확인할 수 있습니다. (callback hell)
  • 코드구조가 복잡하다는 것은 코드를 이해하는데 시간이 걸리는 것이라 볼 수 있습니다.  
  • 이렇게 비동기 처리 코드 개발의 불편함을 간소화하고자 ES8(ECMAScript 2017) 에 async & await 문법이 추가되었습니다. 

 

# async & await 사용 및 확인사항

  • async & await 은 ES8 에 추가 된 표준 문법이며, ES6+ 미지원 브라우저에서 사용하려면 js transpiler 를 통해 변환 해야합니다.
  • 비동기 로직을 포함하는 함수 정의 앞에 async 예약어를 붙여 해당 함수를 async function 으로 만들어 줍니다.
  • 그 다음, 비동기 로직을 수행하는 함수 호출문 앞에 await 예약어를 붙여줍니다.
  • 여기서 비동기 로직을 수행하는 함수는 반드시 Promise 객체를 반환해야 합니다. 
  • async function 의 반환 값은 Promise 객체가 됩니다. 
  • 즉, async function 을 호출하는 함수에도 async & await 전파가 발생하게 됩니다.

foo() 함수는 async function 이므로 Promise 객체를 반환한다.

 

 

# async & await 방식과 Promise chain 방식을 사용한 코드 비교

  • async & await 방식을 사용한 코드 (+ try ~ catch ~ finally 를 사용한 에러핸들링)

const getData = async function() {
  let isLoading = true;
  
  try {
    const result = await fetchData();
    console.log("result: ", result);
    
  } catch(e) {
    console.error("catch: ", error);
    
  } finally {
    console.log("finally");
    isLoading = false;
  }
}

getData();

 

  • Promise chain 방식을 사용한 코드 (+ Promise chain 방식의 에러핸들링)

const getData = function() {
  let isLoading = true;

  fetchData()
  .then(function(result) {
    console.log("promise then: ", result);
  })
  .catch(function(error) {
    console.error("promise catch: ", error);
  })
  .finally(function() {
    console.log("promise finally");
    isLoading = false;
  });
};

getData();

 

  • ES6 Promise 경험이 있는 개발자라면 Promise chain 방식의 코드를 이해하는데 크게 문제가 없을 수 있습니다.
  • 하지만, ES6 Promise 경험이 없는 개발자라면 아무래도 async & await 방식의 코드 이해가 더 편할 거라 생각됩니다.

 

 

# async & await 내부 동작방식 

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
    
  } catch (error) {
    reject(error);
    return;
  }
  
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function () {
    var self = this,
        args = arguments;
        
    return new Promise(function (resolve, reject) {
      var gen = fn.apply(self, args);
      
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
      }
      
      _next(undefined);
    });
  };
}

const getData = /*#__PURE__*/ (function () {
  var _ref = _asyncToGenerator(function* () {
    let isLoading = true;

    try {
      const result = yield fetchData();
      console.log("result: ", result);
      
    } catch (e) {
      console.error("catch: ", error);
    } finally {
      console.log("finally");
      isLoading = false;
    }
  });

  return function getData() {
    return _ref.apply(this, arguments);
  };
})();

getData();
  • Babel transpiler es2017 preset 을 적용해 변환 된 코드입니다.
  • getData() 함수의 내부 로직은 ES6 generator function 으로 구현 된 것을 확인할 수 있습니다.
  • 비동기 로직 함수의 결과를 확인할 수 있도록 yield 를 사용한 것을 확인할 수 있습니다.  

 

 

 

# 참고문서

 

async function

async function 선언은 AsyncFunction객체를 반환하는 하나의 비동기 함수를 정의합니다. 비동기 함수는 이벤트 루프를 통해 비동기적으로 작동하는 함수로, 암시적으로 Promise를 사용하여 결과를 반환

developer.mozilla.org

 

 

 

# 잘못된 내용은 댓글 남겨주세요.

0 Comments
댓글쓰기 폼