23-08-03 forEach와 비동기
문제설명
req.body에서 받아온 객체의 데이터를 배열화 한 다음에 forEach로 데이터베이스와 body의 데이터가 유효한지 검증하는 로직을 설정했다. 하지만 에러가 발생했고 console.log로 forEach의 인자를 찍어보았다.
그리고 Promise {pending}이라는 결과를 얻었다.
시도
forEach는 배열의 모든 요소마다 설정한 로직을 수행하는 기능이다. 여기서 중요한 점은 forEach는 로직을 수행하기만 할 뿐 각 로직에 대한 결과의 출력을 기다리지 않는다. 그래서 가장 먼저 시작한 로직이 가장 늦게 될 수도 있는 것이고 나중에 시작된 로직이 먼저 결과를 출력할 수도 있는 것이다. 즉 forEach는 비동기적 함수라는 의미이다.
Promise {pending}은 로직의 진행 순서를 말한다. pending은 준비를 뜻 한다. 아직 로직이 시작하지 않았다는 것이다.
준비상태가 끝나면 fulfill과 reject 단계로 나뉜다. fulfill은 진행을 의미하고 reject 는 거부를 의미한다.
fulfill은 결과를 출력하거나 동기적인 함수가 있다면 그 함수를 실행한다, 아니면 다시 pending 단계를 거처서 .then()이나 .catch()의 단계로 진행할 수 있다
.
reject는 바로 .then()이나 .catch()의 단계를 거치거나 에러핸들링의 단계로 진행한다.
forEach자체에 async await를 사용해서 로직이 수행이 되야 다음 로직이 수행되도록 할 예정이다.
해결
itemOrderList.forEach(async(itemOrder) => {
const existingItem = await Item.findOne({ where: { id: itemOrder[0] } });
console.log(existingItem)
if (existingItem==null) {
return {
status: 400,
errorMessage: "판매하지 않는 상품이 존재합니다.",
};
}
if (existingItem.amount < itemOrder[1]) {
return {
status: 400,
errorMessage: `${existingItem.name}의 재고가 주문량 보다 적게 있습니다.`,
};
}
});
화살표 함수의 형식으로 forEach 내부의 함수 자체에 async await를 부여해서 로직이 단계적으로 작동이 되도록 했다.
알게된 점
1.forEach는 비동기적 메서드이기 때문에 다른 함수가 포함이 된다면 pending을 야기한다.
2.forEach의 pending을 방지하기 위해서는 async await를 forEach의 내부함수에 적용해야한다.
3.pending=>fulfill/reject 의 관계를 이해할 수 있었다.