async/await로 콜백 지옥 탈출하기
문제 상황
사용자 인증 후 프로필 조회, 권한 체크, 로그 기록을 순차적으로 처리하는 API를 작성하던 중 Promise 체이닝이 길어지면서 에러 핸들링이 복잡해졌다.
function getUserData(userId) {
return authenticate(userId)
.then(user => checkPermission(user.id))
.then(permission => {
if (!permission.allowed) throw new Error('No permission');
return getProfile(permission.userId);
})
.then(profile => logAccess(profile.id).then(() => profile))
.catch(err => handleError(err));
}
async/await 적용
Node 8부터 정식 지원되는 async/await를 사용해 동기 코드처럼 작성했다.
async function getUserData(userId) {
try {
const user = await authenticate(userId);
const permission = await checkPermission(user.id);
if (!permission.allowed) {
throw new Error('No permission');
}
const profile = await getProfile(permission.userId);
await logAccess(profile.id);
return profile;
} catch (err) {
handleError(err);
}
}
결과
- 코드 가독성이 크게 개선됨
- try-catch로 에러 핸들링 일관성 확보
- 중간 변수 활용이 자유로워져 디버깅 편의성 증가
주의사항
병렬 처리가 필요한 경우 Promise.all을 함께 사용해야 한다. await를 순차적으로 사용하면 불필요하게 대기 시간이 늘어난다.
// 병렬 처리
const [user, settings] = await Promise.all([
fetchUser(id),
fetchSettings(id)
]);
ES2017 스펙이지만 Babel 트랜스파일 없이 Node 8에서 바로 사용 가능한 점이 마음에 든다.