Node 7.x에서 --harmony 없이 async/await 쓸 수 있게 됨. 6.10 LTS에선 아직 flag 필요하긴 한데, 7.6부터는 기본 활성화. 프로덕션 API 하나 이걸로 작성하면서 느낀 것들.
promise chain 지옥을 벗어나니까 확실히 코드가 읽힘:
// before (promise chain)
function getOrder(id) {
return db.Order.findById(id)
.then(order => {
return db.User.findById(order.userId)
.then(user => ({ order, user }));
})
.then(({ order, user }) => {
return api.tracking(order.shipmentId)
.then(tracking => ({ order, user, tracking }));
});
}
// after
async function getOrder(id) {
const order = await db.Order.findById(id);
const user = await db.User.findById(order.userId);
const tracking = await api.tracking(order.shipmentId);
return { order, user, tracking };
}
운영에서 배운 것들:
1. error handling은 try/catch. 안 감싸면 unhandledRejection 뜨고 메모리 새기 시작. express 핸들러는 래퍼 하나 만들어서 씀:
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
app.get('/orders/:id', asyncHandler(async (req, res) => {
const result = await getOrder(req.params.id);
res.json(result);
}));
2. 병렬화 놓치기 쉬움. 위 예시처럼 await를 줄줄이 쓰면 순차 실행이라 느림. 병렬 가능한 건 Promise.all로 묶어야 함:
const [user, tracking] = await Promise.all([
db.User.findById(order.userId),
api.tracking(order.shipmentId)
]);
3. 스택 트레이스. async 함수는 예전 callback/promise보다 스택이 잘 남음. 7.x에서 꽤 개선된 편. 그래도 async_hooks 같은 도구는 아직 실험적.
4. V8 버전. Node 7은 단명 (LTS 아님). 6 LTS 쓰려면 --harmony-async-await. 8이 4월 릴리즈 예정이고 곧 LTS 전환될테니 정식 production 이관은 8 나온 다음이 안전.
코드 리뷰 때 await 붙이고 Promise.all로 묶는 타이밍 훈련만 되면 생산성 상승이 체감됨. callback hell 시절에서 정말 많이 왔다.