Promise
지금까지는 콜백 함수를 통해 비동기 상황을 해결했다. 하지만 콜백 함수들이 여러 번 중첩되면 코드가 복잡해지고 가독성이 떨어지는 콜백 지옥 현상이 발생한다. 이 현상을 해결하기 위해 Promise를 사용한다.
new Promise로 프로미스 객체를 생성하고, resolve와 reject를 파라미터로 갖는 콜백 함수를 넣는다.
이 프로미스 변수에는 then과 catch 메서드가 있다. resolve가 호출되면 then이 실행되고, reject가 호출되면 catch가 실행된다. resolve와 reject에 넣어준 인수가 각각 then과 catch로 전해진다.
then이나 catch에서 다시 다른 then이나 catch를 붙일 수 있다. 이것을 promise chaining이라고 하며, 이전 then의 return 값을 다음 then의 파라미터로 넘긴다. 프로미스를 return한 경우 프로미스가 수행된 후 다음 then이나 catch가 호출된다.
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료"), 3000);
}).then((result) => {
console.log(result); // 완료
return result + "!!!!!";
},
(error) => { }
).then((result) => {
console.log(result); // 완료!!!!!
},
(error) => { }
)
async/await
프로미스가 콜백 지옥 현상은 해결했지만 then과 catch가 계속 반복되기 때문에 여전히 코드가 복잡하다. async/await 문법은 코드를 더 깔끔하게 줄여준다.
async
비동기 함수임을 나타내는 키워드로, 함수 앞에 async 키워드를 넣어주면 된다.
async 함수는 무조건 Promise 객체를 반환한다. 반환 값이 Promise가 아니라면 Promise로 감싸서 return 반환해준다.
아래 코드에서 f 함수의 return 7은 return Promise.resolve(7)과 동일하다.
async function f() {
return 7; // return Promise.resolve(7)과 동일
}
f().then(
function (result) {
console.log("promise resolve: ", result);
},
function (error) {
console.log("promise reject: ", error);
}
)
await
await는 async 함수 안에서만 동작할 수 있고, 프로미스 then() 메서드를 좀 더 쉽게 사용할 수 있게 해 준다.
promise 객체가 일을 다 할 때까지 기다리라는 의미를 가진다.
async function f() {
let promise1 = new Promise(function (resolve, reject) {
setTimeout(() => resolve("첫 번째 쿼리"), 3000)
});
let result1 = await promise1;
console.log(result1); // 첫 번쨰 쿼리
let promise2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve("두 번째 쿼리 " + result1), 3000)
});
let result2 = await promise2;
console.log(result2); // 두 번째 쿼리 첫 번째 쿼리
let promise3 = new Promise(function (resolve, reject) {
setTimeout(() => resolve("세 번째 쿼리 " + result2), 3000)
});
let result3 = await promise3;
console.log(result3); // 세 번쨰 쿼리 두 번째 쿼리 첫 번째 쿼리
}
f();
주문하기 API 수정
이전 코드는 비동기 문제를 해결하지 못해서 deliveryId와 orderId를 제대로 받아오지 못했었다. async/await로 다음 코드와 같이 수정하면 모든 쿼리가 우리가 원하는 대로 동작한다.
const order = async (req, res) => {
const conn = await mariadb.createConnection({
host: 'localhost',
user: 'root',
database: 'Bookshop',
password: 'root',
dateStrings: true
});
const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
let deliveryId, orderId;
// delivery 테이블 삽입
let sql = `INSERT INTO delivery (address, receiver, contact)
VALUES (?, ?, ?)`;
let values = [delivery.address, delivery.receiver, delivery.contact];
let [results] = await conn.query(sql, values);
deliveryId = results.insertId;
// orders 테이블 삽입
sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
VALUES (?, ?, ?, ?, ?)`
values = [firstBookTitle, totalQuantity, totalPrice, userId, deliveryId];
[results] = await conn.query(sql, values);
orderId = results.insertId;
// orderedBook 테이블 삽입
sql = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`;
values = [];
items.forEach((item) => {
values.push([orderId, item.bookId, item.quantity]);
});
[results] = await conn.query(sql, [values]);
// 응답 전송
res.status(StatusCodes.CREATED).json(results);
};
배운 점
- Node.js에서 비동기를 처리하는 방법은 3가지가 있다.
- 콜백 함수
- Promise (resolve, reject)
- async/await
- Promise를 사용할 때 then이나 catch에서 다시 다른 then이나 catch를 붙일 수 있다. 이것을 promise chaining이라고 하며, 이전 then의 return 값을 다음 then의 파라미터로 넘긴다.
- await는 async 함수 안에서만 동작할 수 있다.
'데브코스' 카테고리의 다른 글
[8주차 - DAY5] 주문 API 구현 (0) | 2024.04.19 |
---|---|
[8주차 복습 발표] 비동기 처리 (1) | 2024.04.18 |
[8주차 - DAY3] 주문 API 구현 (0) | 2024.04.17 |
[8주차 - DAY2] 장바구니 API 구현 (0) | 2024.04.16 |
[8주차 - DAY1] 도서 API 구현(3) (0) | 2024.04.15 |