노드 7.6부터 지원되는 기능 이며 ES2017에서 추가되어 알아두면 정말 편리한 기능 이다. 특히 노드처럼 비동기 위주로 프로그래밍 할때 도움이 된다.
프로미스가 콜백 지옥을 해결했다지만 여전히 코드가 장황하고 then 과 catch가 계속 반복되기 때문이다. async/await 문법은 프로미스 를 사용한 코드를 한번 더 깔끔하게 줄인다.
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
// 생략
})
.catch(err => {
console.error(err);
});
}
콜백과 다르게 코드의 깊이가 깊어지진 않지만, 코드는 여전히 길다.
async/await 문법을 사용하면 다음과 같이 바꿀수 있다.
async function이라는 것이 추가된다.
async function findAndSaveUser(Users) {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
}
놀라울정도로 코드가 짧아졌다.
함수 선언부를 일반 함수 대신 async function으로 교체한 후 프로미스 앞에 await을 붙인다.
이제 함수는 해당 프로미스가 resolve될 때까지 기다린 다음 로직으로 넘어간다 예를 들면 await User.findOne({})이 resolve될때까지 기다린다음에 user 변수를 초기화 하는것이다.
위코드는 에러를 처리하는 부분(프로미스가 reject된 경우)이 없으므로 다음과 같은 추가 작업이 필요하다
async function findAndSaveUser(Users) {
try {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
} catch (error) {
console.error(error);
}
}
try/catch문으로 로직을 감쌌다. 프로미스의 catch 메서드 처럼 try/catch 문의 catch가 에러를 처리한다.
화살표함수도 async와 같이 사용할수있다.
const findAndSaveUser = async (Users) => {
try {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
} catch (error) {
console.error(error);
}
};
for문과 async/await을 같이써서 프로미스를 순차적으로 실행할수있다. for문과 함께 쓰는것은 노드 10버전부터 지원하는 ES2018 문법이다.
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
(async () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
for await if 문을 사용해서 프로미스 배열을 순회하는 모습이다. async 함수의 반환값은 항상 promise로 감싸진다 따라서 실행 후 then을 붙이거나 또 다른 async 함수 안에서 await을 붙여서 처리할수있다.
async function findAndSaveUser(Users) {
// 생략
}
findAndSaveUser().then(() => { /* 생략 */ });
// 또는
async function other() {
const result = await findAndSaveUser();
}
앞으로 중첩되는 콜백 함수가 있다면 프로미스를 거쳐 async/await 문법으로 바꾸는 연습을 해봐야겠다.