티스토리 뷰
비동기 프로그래밍으로 발생하는 콜백지옥을 해결하는 방법으로 ES6에서 추가된 Promise를 사용하는 방법이 있습니다. ([자바스크립트] 비동기프로그래밍 - 콜백함수(Callback function) 참고) 이번 포스트에서는 비동기 프로그래밍을 처리할 수 있는 방법으로 async
와 await
에 대해 이야기 하려 합니다.
1. 문법
async function name([param[, param[, ... param]]]) {
statements
}
- name: 함수 이름
- param: 함수에 전달되는 인자들의 이름
- statements: 함수 본문
- 리턴 값: async 함수의
return
값으로resolve
된Promise
객체 혹은 async 함수에서 예외가 발생하였다면 발생 된 예외로reject
된Promise
객체
async 함수를 사용하는 방법은 기본 함수를 생성하는 것과 큰 차이가 없습니다. 그렇기 때문에 Promise
를 이용하는 것보다 async
, await
를 사용할 때 코드가 더 간결해 질 수 있습니다. async 함수의 리턴 값은 resolve
된 Promise
객체, 혹은 reject
된 Promise
객체를 암묵적으로 리턴합니다. 암묵적으로 리턴한다는 말은, new Promise
를 사용하여 Promise
객체를 리턴하지 않아도 async 함수의 리턴 값으로 Promise
객체를 받게 된다는 뜻으로 사용하였습니다.
* 참고 - 리턴 값 확인하기
2. 데모
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
var result = await resolveAfter2Seconds();
console.log(result);
// expected output: 'resolved'
}
asyncCall();
3. 설명
async 함수에서는 await
를 사용할 수 있습니다. await
는 async 함수에서만 사용 가능합니다. 일반 함수에서 await
를 사용하게 되면 syntax error가 발생됩니다.
await
는 Promise
와 함께 사용되어야 합니다. await
를 사용하면 Promise
가 종료 될 때까지 함수 실행이 일시 정지 됩니다. 그후 Promise
가 종료 되면 함수 실행이 다시 진행 됩니다. await
사용하면 Promise
에서 resolve
된 값을 반환 받게 됩니다. await
의 Promise
가 reject
되면, 예외가 발생됩니다.
function awaitFunction() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('success'), 1000);
// setTimeout(() => reject('fail'), 1000);
});
}
async function asyncFunction() {
try {
const msg = await awaitFunction();
console.log(msg); // awaitFunction에서 resolve가 호출 될 때 resolve의 인자값 'success'
} catch (e) {
console.log(e); // awaitFunction에서 reject가 호출 될 때 reject의 인자값 'fail'
}
}
asyncFunction();
Promise
의 사용 방법을 단순히 하기 위해서(Promise
의 콜백 함수 동작을 단순히 보이기 위해서) async
와 await
가 사용됩니다.
var resolveAfter2Seconds = function() {
console.log("starting slow promise");
return new Promise(resolve => {
setTimeout(function() {
resolve(20);
console.log("slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise");
return new Promise(resolve => {
setTimeout(function() {
resolve(10);
console.log("fast promise is done");
}, 1000);
});
};
var sequentialStart = async function() {
console.log("==SEQUENTIAL START==");
// If the value of the expression following the await operator is not a Promise, it's converted to a resolved Promise.
const slow = await resolveAfter2Seconds();
const fast = await resolveAfter1Second();
console.log(slow);
console.log(fast);
}
var concurrentStart = async function() {
console.log("==CONCURRENT START with await==");
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second();
console.log(await slow);
console.log(await fast); // waits for slow to finish, even though fast is already done!
}
var stillSerial = function() {
console.log("==CONCURRENT START with Promise.all==");
Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then(([slow, fast]) => {
console.log(slow);
console.log(fast);
});
}
var parallel = function() {
console.log("==PARALLEL with Promise.then==");
resolveAfter2Seconds().then((message)=>console.log(message)); // in this case could be simply written as console.log(resolveAfter2Seconds());
resolveAfter1Second().then((message)=>console.log(message));
}
sequentialStart(); // takes 2+1 seconds in total
// wait above to finish
setTimeout(concurrentStart, 4000); // takes 2 seconds in total
// wait again
setTimeout(stillSerial, 7000); // same as before
// wait again
setTimeout(parallel, 10000); // trully parallel
위의 예제는 MDN에 나와 있는 async
, await
예제입니다. 코드가 길고 복잡해 보이지만 뜯어 보면 어렵지 않은 코드입니다.
resolveAfter2Seconds
: 2초후Promise.resolve
로 20을 내보내는 함수입니다.resolveAfter1Second
: 1초후Promise.resolve
로 10을 내보내는 함수입니다.sequentialStart
:resolveAfter2Seconds
와resolveAfter1Second
를await
를 이용하여 순차적으로 결과를 받는 함수입니다. 순차적으로 결과를 받기 때문에, 2초(resolveAfter2Seconds
) + 1초(resolveAfter1Second
) = 3초 후console.log
출력 값을 확인 할 수 있습니다.concurrentStart
:resolveAfter2Seconds
와resolveAfter1Second
를 동시(엄밀히 말하면 동시는 아니지만..) 실행하고 그 후await
로 결과를 받는 함수입니다. 동시에 함수들이 실행 되기 때문에 가장 마지막으로 종료 되는 2초(resolveAfter2Seconds
) 후console.log
출력 값을 확인 할 수 있습니다.stillSerial
:Promise.all
을 사용하여concurrentStart
와 동일한 기능을 구현한 함수입니다.parallel
: 병렬로resolveAfter2Seconds
와resolveAfter1Second
를 실행하는 함수입니다.
참고
'JavaScript' 카테고리의 다른 글
[자바스크립트] ES6(ECMA Script6) - export, import (6) | 2017.02.13 |
---|---|
[자바스크립트] 정규식(Regular Expressions) (10) | 2017.02.08 |
[자바스크립트] ES6(ECMA Script 6) - for ... of 문 (0) | 2017.01.20 |
[자바스크립트] ES6(ECMA Script 6) - 화살표 함수(Arrow function) (3) | 2017.01.19 |
[자바스크립트] ES6(ECMA Script 6) - 구조분해 할당(Destructuring assignment) (7) | 2017.01.18 |