[JavaScript] async-await 뜯어보기

moonee·2021년 10월 14일
2

자바스크립트

목록 보기
7/7

비동기 처리를 마치 동기적인 것 처럼 처리하게 해주는 async/await은 사실 Generator와 Promise 로 구현되어있다.

function getName(){
  	return new Promise((resolve,reject)=> {
    	resolve('Kim');
    });
}


async function test(){
  	let name = await getName();
  	console.log(name);
}

위의 async/await으로 구현된 코드를 ES6 코드로 변환하면 아래와 같다.


let test = (() => {
  var ref = _asyncToGenerator(function* () {
    let name = yield getName();
    console.log(name);
  });

  return function test() {
    return ref.apply(this, arguments);
  };
})();

function _asyncToGenerator(fn) {
  return function () { 
    var gen = fn.apply(this, arguments); 
    return new Promise(function (resolve, reject) {
      function step(key, arg) { 
        try { 
          var info = gen[key](arg); 
          var value = info.value; 
        } catch (error) { 
          reject(error); return; 
        } 
        if (info.done) { resolve(value); } 
        else { 
          return Promise.resolve(value)
                 .then(function (value) { 
            return step("next", value); }, 
                       function (err) { 
            return step("throw", err); }); 
        } 
      } return step("next"); }); 
  }; 
}

function getName() {
  return new Promise((resolve, reject) => {
    resolve('Kim');
  });
}

test();

... 너무 기니까 변환된 함수 하나씩 살펴보자..

0. test

let test = (() => {
  var ref = _asyncToGenerator(function* () {
    let name = yield getName();
    console.log(name);
  });

  return function test() {
    return ref.apply(this, arguments);
  };
})();
  • test 함수가 즉시실행되어 test 함수를 반환한다.

  • 아래에서 설명할 _asyncToGenerator 함수의 인자로 제너레이터 함수를 전달한다.

  • 해당 제너레이터 함수에서는 Promise를 반환하는 getName 함수를 호출 후 실행 될 때 까지 yield 한 후, console.log(name)을 실행한다. 이는 기존 test 함수에서 await 의 역할을 yield 가 하고 있고 그에 따라서 Promise 반환 후 console.log(name)의 실행이 보장됨을 알 수 있다.

  • 이렇게 제너레이터로 변환된 함수에 this 바인딩을 하여 호출한다.

1. async to Generator

위에서 사용된 함수이다.

function _asyncToGenerator(fn) {
  return function () { 
    var gen = fn.apply(this, arguments); 
    return new Promise(function (resolve, reject) {
      function step(key, arg) { 
        try { 
          var info = gen[key](arg); 
          // info 예시 
          //{ value: Promise { 'Kim' }, done: false } 
          var value = info.value; 
        } catch (error) { 
          reject(error); return; 
        } 
        if (info.done) { resolve(value); } 
        else { 
          return Promise.resolve(value)
                 .then(function (value) { 
            return step("next", value); }, 
                       function (err) { 
            return step("throw", err); }); 
        } 
      } 
      return step("next"); }); 
  }; 
}
  • 인자로 async-await 동작이 있는 함수를 받는다.

  • 해당 함수에 this binding을 해준 후 해당 함수를 차례로 실행할 Promise를 반환한다.

  • Promise 내부에 정의된 step 함수는 key 값과 arg 를 인수로 받는다.

  • step 함수에서 key 값을 next 혹은 throw로 받아gen[key](arg)로 접근하므로써 gen.next(arg) || gen.throw(err)를 호출 된다.

  • 이 때 info.done 이 true더 이상 처리될 다음 단계가 없다는 것이므로 resolve로 최종 리턴이 되고, false아직 완료되지 않은 비동기 처리가 있다는 것이므로 value를 실행 후 다시 step("next", arg)를 호출하여 다음 단계를 차례대로 실행 한다.
    - 비동기 작업의 경우 value에 Promise 형태로 저장되어 있으므로 Promise.resolve를 통해 작업을 완료해준다.

코드는 여기서 컴파일했다

profile
기록

2개의 댓글

comment-user-thumbnail
2021년 10월 14일

여기있는 영상들도 참고해보시면 좋을 것 같아요 ㅎㅎ
https://www.youtube.com/watch?v=H_Hb9IF7sfc
https://www.youtube.com/watch?v=GvuoY_vXJn4

1개의 답글