자바스크립트의 비동기를 다루는 async/await
콜백함수의 콜백지옥을 탈출하게 해주는 Promise, 그리고 또 Promise의 단점을 보완해주는 async/await.
async/await은 Promise와 다른 개념이 아니고 Promise를 사용하는 패턴이니 Promise의 이해가 선행되어야 합니다.
Promise 포스팅 참고하기
인간의 욕심은 끝이 없고 보완의 보완을 거듭하는 패턴은 계속 나옵니다.
현재 비동기 연산을 다루는 패턴 중 가장 쉽게 접근할 수 있는 방법인 async/await는 비동기 처리의 꽃 이라고 할 수 있습니다.
왜 callback, promise로도 비동기 처리가 가능한데, async/await까지 알아야 할까요?
가장 큰 이유는 여전히 Promise도 가독성이 썩 좋지 않다는 점입니다. 코드가 깔끔하고 가독성이 좋아야 눈으로 로직 파악이 가능하고 디버깅이 쉬워지기 때문 이죠. 그리고 또 async/await로 코드의 양도 줄일 수 있습니다.
const makeRequest = () =>
getJSON()
.then(data => {
console.log(data);
return "done";
})
makeRequest();
먼저 Promise로 작성된 makeRequest()라는 함수를 살펴봅시다.
const makeRequest = async () => {
console.log(await getJSON());
return "done";
}
makeRequest();
그리고 이건 async/await으로 작성된 똑같은 코드입니다. 이 쪽이 훨씬 더 깔끔하고 직관적이지 않나요.
async 사용하기
function workP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Date().toISOString());
}, sec*1000);
});
}
function justFunc() {
return 'just Function';
}
async function asyncFunc() {
return 'async Fucntion';
}
console.log(justFunc());
console.log(asyncFunc());
console.log(workP());
여기 3가지의 함수가 있습니다.
workP() : Promise로 구현된 함수
justFunc() : 일반 함수
asyncFunc() : async를 사용한 함수
이 세 함수의 정보를 로그에 찍어보면 이와 같습니다.
일반 함수인 justFunc()은 리턴으로 준 문자열 'jusf function'이 그대로 리턴되지만,
asyncFunc()과 workP()는 둘 다 Promise 객체를 리턴하는 것을 확인할 수 있습니다.
async는 Promise객체를 리턴하기 때문이죠.
async function asyncFunc() {
return 'return value';
}
asyncFunc().then((result) => {
console.log(result)
});
Promise객체를 리턴하기 때문에 .then()을 연결해 다음 동작을 넣을 수 있습니다. 여기서 .then의 파라미터로 넘겨준 result는 asyncFunc()에서 리턴하는 값이고, 이를 Promise의 then으로 받게됩니다.
async는 함수를 선언할 때 앞에 붙이고 그 함수를 Promise를 리턴하는 함수로 만들어줍니다. 그 전에는 new Promise()를 통해서 Promise 객체를 만들어주고 Promise를 리턴했지만, 그 과정을 숨길 수 있게 되어 코드가 짧아졌습니다. 또 Promise에서 사용했던 resolve는 async/await에서 return과 동일합니다.
await 사용하기
function workP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('workP function');
}, sec*1000);
});
}
async function asyncFunc() {
const result_workP = await workP(3);
console.log(result_workP);
return 'async function';
}
asyncFunc().then((result) => {
console.log(result)
});
asyncFunc()을 보면, 여기서 workP()의 결과가 나중에 리턴된 것을 볼 수 있고 이는 비동기식으로 함수가 실행되었다는 것을 의미합니다. 여기서 workP()의 결과를 받은 후에 asyncFunc()을 실행하고 싶다면 어떻게 해야할까요? 이때 사용하는 것이 바로 await입니다.
async function asyncFunc() {
await workP(3);
return 'async function';
}
workP()함수를 호출하기 전에 await만 걸어 실행해 봅니다. 그러면 3초 뒤에 'aync function' 문자열이 콘솔에 찍히게 되는데, 이는 workP()실행 후 asyncFunc()이 실행되었고 동기적으로 코드가 실행된 것을 확인할 수 있습니다.
function workP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('workP function');
}, sec * 1000);
});
}
async function asyncFunc() {
const result_workP = await workP(3);
console.log(result_workP);
return 'async function';
}
asyncFunc().then((result) => {
console.log(result)
});
await을 붙이면 await이 붙은 함수의 실행이 끝나는 동안 기다리게 되므로 다음 코드를 실행할 수 없게 됩니다. 그리고 await을 붙인 함수의 결과 값을 변수에 넣어 위 예제처럼 출력할 수 있고 then을 이용해 다음 로직을 연결해 주어도 됩니다.