어제는 order.js파일에서 주문하는 로직을 위해서 여러 sql문을 한번에 사용할려고 했다.
그래서 db에 multipleStatements: true를 이용해서 사용하였는데, 이번에는 async/await를 배워 주문들이 차례대로 사용될 수 있도록 하면서, .insertId를 sql을 하나씩 넣은 id를 사용할 수 있도록 구현하였다.
Node.js의 특징은 싱글 스레드, 이벤트 기반, 논블로킹I/O가 있다.
이 중 논블로킹 I/O가 한명이 일을 하는데, 요리르 순차적으로 하는게 아니라 중간중간 비는 시간이 있으면, 다른 요리를 해야하는 것에 비유를 했었다. 근데 사실은 그냥 다 같이 실행한다고 생각하면 좋다.
그것때문에 배달정보를 넣는 과정에서 db에 데이터를 넣는거 보다, 그 밖에서 console.log한게 더 빠르게 나오는것이다.
비동기가 발생하는 것은 코드가 기다려야 하는 시간이 생긴다는 의미이다.
즉, query()를 기다리는 동안 다른 일을 하는 거 때문에 console.log가 먼저 출력되는 거다.
ex. setTimeOut(), setInterval(), query()
비동기 처리는 비동기가 필요없을 때 사용하는 방법으로 이전 코드들의 시간을 다 기다려줘요. 순서를 맞춰서 코드를 실행해주겠다.
1. 콜백 함수: 작업 완료 후 호출할 함수를 넘겨 실행 순서를 보장한다.
2. promise(resolve, reject): 비동기 작업의 성공 또는 실패를 처리할 수 있는 객체이다.
3. then & catch: promise 객체의 후속 작업을 지정해, 성공과 실패를 처리한다.
4. ES2017 promise => async & await: Promise를 더 간단하게 사용할 수 있도록 도와주는 문법으로, 동기 코드처럼 읽히면서 비동기 처리를 가능하게 한다.
promise는 자바스크립트에서 비동기 작업을 관리하기 위한 객체입니다. 비동기 작업을 실행하는 동안 결과가 바로 나오지 않을 수 있게되어 순서를 정할 수 있게 된다.
let promise = new Promise(function(resolve, reject) {
// 비동기 작업 시작: 3초 후 작업 성공 시 resolve 호출
setTimeout(() => {
resolve("완료!");
}, 3000);
});
let promise = new Promise(function(resolve, reject) {
// 비동기 작업 시작: 3초 후 작업 성공 시 resolve 호출
setTimeout(() => {
resolve("완료!");
}, 3000);
// 작업 중 문제가 생기면 reject를 호출해 에러를 반환할 수 있음
});
Promise 객체를 좀 더 쉽고 편하게 사용하는 문법으로 비동기 처리를 쉽게한다.
async는 2가지 기능이 있다.
async function first() {
return 7; // Promise 객체를 반환 중
// async의 첫번째 기능
// async 함수는 무조건 Promise객체를 반환
// - 만약 변환값이 Promise가 아니면, Promise.resulve()로 감싸서 보낸다.
}
first().then(
function (result){
console.log(" promise resolve: ", result);
},
function (error){
console.log(" promise reject: ", result);
}
)
first();
// 3초
// promise resolve:7
async function second() {
// Promise 객체 한개당 => query 하나
let promise1 = new Promise(function(resolve, reject) {
setTimeout(()=> resolve("첫번째 쿼리!"),3000)
});
let result1 = await promise1;
// promise 객체가 일 다 할때까지 기다려줌
console.log(result1);
let promise2 = new Promise(function(resolve, reject) {
setTimeout(()=> resolve("두번째 쿼리! with" + result1),3000)
});
let result2 = await promise2;
console.log(result2);
let promise3 = new Promise(function(resolve, reject) {
setTimeout(()=> resolve("세번째 쿼리! with" + result2),3000)
});
let result3 = await promise3;
console.log(result3);
}
second();
// 각각 3초씩 9초걸림
// 첫번째 쿼리!
// 두번째 쿼리! with 첫번째 쿼리!
// 세번째 쿼리! with 두번째 쿼리! with 첫번째 쿼리!
코드에 적용하기 위해서 async와 query()문에 await을 적었지만 오류가 났다.
그래서 mysql2사이트를 통해서 다음과 같이 사용해야함을 알 수 있었다.
이전에 쓰던 mysql.createConnection({})을 사용할 때는, 코드안에 작성해야 하는데, mysql.createPool을 사용하면 다른 파일에서도 관리할 수 있다고 한다.
해당 문서를 통해서 다음과 같이 코드를 수정할 수 있었다.
수정 후 코드
const order = async (req,res)=>{
try{
const {user_id, items, delivery, totalQuantity, totalPrice} = req.body;
let deliveryId;
if (delivery.id){
deliveryId = delivery.id;
} else {
// 배달 정보 넣기
const sqlDelivery = `INSERT INTO delivery (address, receiver, contact) VALUES (?,?,?);`;
const valuesDelivery = [delivery.address, delivery.recevier, delivery.contact];
const [deliveryResult] = await db.query(sqlDelivery, valuesDelivery);
deliveryId = deliveryResult.insertId;
}
// 주문서
let sqlOrder = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id) VALUES ((SELECT title FROM books WHERE id = ?), ?, ?, ?, ?);`;
let valuesOrder = [items[0].bookId, totalQuantity, totalPrice, user_id, deliveryId];
let [newOrderId] = await db.query(sqlOrder, valuesOrder);
for(const item of items){
// orderItems 추가하기
const sqlOrderItems = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES (?,?,?);`;
const valuesOrderItems = [newOrderId.insertId, item.bookId, item.quantity]
await db.query(sqlOrderItems,valuesOrderItems)
// 장바구니 삭제
const sqlDeleteCart = `DELETE FROM cartItems WHERE id = ?;`;
const valuesDeleteCart = [item.cartItemId];
await db.query(sqlOrderItems,valuesOrderItems)
}
return res.status(StatusCodes.OK).json({ newOrderId })
}catch(err){
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
}