시리즈 목차
이 글은 시리즈 글입니다. 이번 글에서는 자바스크립트에서 비동기 작업을 더 쉽게 다룰 수 있는 방식인 async await 에 대해 알아볼 것입니다. 기본적으로 자바스크립트가 비동기로 동작하지 않는다는 사실과 비동기룰 다루던 첫 형태인 콜백함수, 그 콜백 함수를 더 쉽게 다루기 위해 등장한 프로미스는 저번 글에서 다루었습니다! 자바스크립트가 비동기함수를 어떻게 처리하는지 동작 원리를 모르시는 분과 콜백함수, 프로미스가 뭔지 잘 모르겠다 하시는 분들은 이전 글을 참고해보세요!
- Javascript는 비동기를 어떻게 처리해 - 동작 원리
- Javascript는 비동기를 어떻게 처리해 - 콜백 함수
- Javascript는 비동기를 어떻게 처리해 - 프로미스
- Javascript는 비동기를 어떻게 처리해 - async await
Async/await
Async/await 함수를 사용하는 목적은 여러 프로미스의 동작을 동기스럽게 사용할 수 있게 해주는 것입니다. 또한 어떤 동작을 여러 프로미스 그룹에서 간단하게 동작하게 하는 것입니다. 프로미스가 구조화된 callback과 비슷한 것처럼, async/await 또한 제너레이터와 프로미스를 묶는 것과 비슷합니다. Async 함수는 항상 AsyncFunction(프로미스) 객체를 반환하는 비동기 함수인데요. 명시적으로 프로미스가 아니라면 암묵적으로 감싸지게 되죠.
예제
async function foo() {
return 1
}
위 코드는 아래와 같습니다. 위 코드는 사람이 저렇게 async 함수를 작성하면 리턴 값을 암묵적으로 프로미스로 감싸주게 되는데, 감싸준 형태가 아래와 같은 것이죠. 즉 사람이 프로미스로 감싸주지 않으면 내부에서 저렇게 감싸진다고 생각하면 됩니다.
function foo() {
return Promise.resolve(1)
}
사용법
Async 함수는 이벤트 루프를 통해 비동기적으로 작동하는 함수죠. 이 함수는 암시적으로 프로미스를 사용해 결과를 반환하게 됩니다. 하지만 Async
함수를 사용하면 동기함수를 사용할 때와 비슷하게 코드를 작성할 수 있습니다.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
위를 보면 async 함수 내에서 await 키워드를 붙여 비동기 함수를 호출하는 것을 볼 수 있습니다. 이 await
는 async 함수 내부에서만 사용할 수 있고, 밖에서 사용한다면 syntax error가 발생하게 됩니다.
예외처리
예외처리 시 이제 then과 catch 문을 쓰지 않아도 됩니다! 동기 스타일로 코드를 작성했던 때처럼 try/catach
를 이용해 에러를 핸들링 할 수 있는 것이죠.
async function getFirstUser() {
try {
let users = await getUsers();
return users[0].name;
} catch (err) {
return {
name: 'default user'
};
}
}
고급 예제
이번엔 여러 비동기 함수를 하나의 async 함수안에서 호출하는 예제를 보도록 하겠습니다. 여기서는 코드를 어떻게 짜냐에 따라 속도면이나 코드의 질이 달라지게 되는데 먼저 잘못된 예시를 한번 봅시다.
var resolveAfter2Seconds = function() {
return new Promise(resolve => {
setTimeout(function() {
resolve(20);
console.log("slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
return new Promise(resolve => {
setTimeout(function() {
resolve(10);
console.log("fast promise is done");
}, 1000);
});
};
var sequentialStart = async function() {
const slow = await resolveAfter2Seconds();
console.log(slow);
const fast = await resolveAfter1Second();
console.log(fast);
}
Async 함수 내에서 await
을 위처럼 연속으로 호출하면 둘은 동시에 await하지 않습니다. 두 번째의 타이머가 첫번째 await에서 2초를 기다리는 동안 생성되지 않는 것이죠. 따라서 이런 식으로 await 호출을 더 하게 될 경우 비동기 함수들을 쭉 기다려가며 실행하게 되어 잘못 만든 함수라고 할 수 있습니다.
var concurrentStart = async function() {
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 stillConcurrent = function() {
console.log('==CONCURRENT START with Promise.all==');
Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
});
}
var parallel = function() {
resolveAfter2Seconds().then((message)=>console.log(message));
resolveAfter1Second().then((message)=>console.log(message));
}
이번에는 동시에 await을 하는 예제를 보겠습니다. 먼저 Concurrent 함수를 봅시다. slow와 fast 에 함수를 담으며 두 타이머가 생성 된 뒤 await 합니다. 이때 slow 가 더 오래(2초를) 기다려야 하므로 2초 후 함수가 종료됩니다. 아래 still concurrent에서는 저번 글에서 소개했던 Promise.all
로 두 개의 비동기 함수를 묶어 줍니다. 이렇게 하면 타이머를 모두 생성하고 await합니다. 앞서 살펴본 concurrent 함수와 같은 결과를 내게 됩니다. 또 이렇게 동시에 두 개 이상의 프로미스를 wait 하고 싶다면 각각 Promise.then
을 사용해도 됩니다. Parallel 함수에서 이를 잘 표현해주고 있죠.
'Develop > 백엔드 & 서버' 카테고리의 다른 글
클로저- 콜백을 구현하는 이상적인 구조 (0) | 2021.01.27 |
---|---|
Javascript는 비동기 함수를 어떻게 처리해 - 프로미스 (0) | 2021.01.20 |
Javascript는 비동기를 어떻게 처리해 - 콜백함수 (0) | 2021.01.20 |
Javascript는 비동기를 어떻게 처리해 - 동작 원리 (0) | 2021.01.19 |
CORS 이슈 해결하기 (0) | 2021.01.18 |
댓글