비동기 처리를 마치 동기적인 것 처럼 처리하게 해주는 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();
... 너무 기니까 변환된 함수 하나씩 살펴보자..
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 바인딩을 하여 호출한다.
위에서 사용된 함수이다.
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를 통해 작업을 완료해준다.
코드는 여기서 컴파일했다
여기있는 영상들도 참고해보시면 좋을 것 같아요 ㅎㅎ
https://www.youtube.com/watch?v=H_Hb9IF7sfc
https://www.youtube.com/watch?v=GvuoY_vXJn4