2024년 10월 14일
: Node.js는 논블로킹 I/O 방식임
비동기 발생 : 일단 이전 시간이 오래 걸리면 기다려주지않고(알아서 하라고 하고) 다음 코드를 무작정 실행함
ex) setTimeOut(), setInterval(), query(), …
이것은 실행되는 코드가 기다려야 하는 시간이 생긴다는 의미
→ 쿼리를 쳐서 데이터베이스에 쿼리를 실행되는데 기다리는 시간이 필요함 (그런데 노드는 쿼리를 기다려주지 않고 그대로 다음코드가 실행됨)
비동기 처리
: Promise 객체는 new 키워드와 Promise 생성자 함수를 사용한다. Promise 생성자 안에 두개의 매개변수를 가진 콜백 함수(executor)를 넣게 되는데, 첫 번째 인수는 작업이 성공했을 때 성공임을 알려주는 객체(resolve)이며, 두 번째 인수는 작업이 실패했을 때 실패(reject)임을 알려주는 객체다.
이렇게 생성한 Promise 객체는 비동기 작업이 완료된 이후에 then(), catch()와 같은 프로미스 핸들러를 통해 다음 작업을 연결시켜 진행할 수 있게 해준다. 이러한 작업을 프로미스 체이닝이라 하고, 프로미스 체이닝이 이뤄지려면 핸들러를 통해 반환되는 값이 프로미스 객체여야 하는데, then 핸들러(성공)로 return 하는 값은 자동으로 프로미스 객체로 감싸져 반환된다.
// promise-demo.js
// Promise 객체 : 무조건 약속을 지키는 친구
// 친구 소환
let promise = new Promise(function(resolve, reject) { // 매개변수로 함수를 받음
// executor : 이 친구가 할 일
setTimeout(() => resolve("완료!"), 3000);
// 일을 다 하면 무조건 콜백함수 resolve() 또는 reject() 둘 중 하나는 호출
// 할 일을 성공적으로 하면 resolve(결과)
// 할 일을 실패하면 reject(에러)
});
// promise-demo.js
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("완료!"), 3000);
});
// then : promise의 기본 메소드. promise가 일 다하고(= 약속 다 지키고) 호출해야하는 함수
promise.then(
function(result){
console.log(result); // 완료!
}, // resolve와 연결됨
function(err){} // reject와 연결됨
);
// promise-chain-demo.js
// 비동기 처리 방식 'Promise (Chaining)'
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("완료"), 3000);
}).then(
function(result){
console.log(result); // 완료
return result + "!!!!!";
},
function(err){}
).then(
function(result){
console.log(result); // 완료!!!!!
return result + "!!!!!";
},
function(err){}
).then(
function(result){
console.log(result); // 완료!!!!!!!!!!
},
function(err){}
);
// async-demo.js
// async-await : Promise 객체를 좀 더 쉽고 편하게 사용하는 문법
// 즉, 비동기 처리가 쉽다!
// async 함수
// function f() {} : 일반 함수
// async function f() {} : async 함수
// async의 첫번째 기능
async function f() {
return 7; // = reutrn Promise.resolve(7)
// async 함수는 무조건 Promise 객체를 반환
// 만약 반환값이 Promise가 아니면, Promise.resolve로 감쌈
}
f().then(
function(result) {
console.log("promise resolve : ", result); // promise resolve : 7
},
function(error) {
console.log("prommise reject : ", error)
}
);
// await-demo.js
// async-await : Promise 객체를 좀 더 쉽고 편하게 사용하는 문법
// 즉, 비동기 처리가 쉽다!
// await은 async 함수 안에서만 동작!
// await이 Promise 객체.then() 이 메소드를 좀 더 쉽게 사용할 수 있는 방법
// async의 두번째 기능
// Promise 객체가 일이 끝날 떄까지 기다릴 수 있는 공간을 제공!
async function f() {
let promise = new Promise(function(resolve, reject){
setTimeout(() => resolve('완료!'), 3000);
});
let result = await promise;
// Promise 객체가 일 다 할때까지 기다려줌
console.log(result); // 완료!
}
f();
// 함수호출 잊지 말아야함!!
// await-demo.js
async function f() {
// promise 객체 한개당 => query 하나
let promise1 = new Promise(function(resolve, reject){
setTimeout(() => resolve('첫번째 쿼리'), 3000);
});
let result1 = await promise1;
console.log(result); // 첫번째 쿼리
// promise 객체 한개당 => query 하나
let promise2 = new Promise(function(resolve, reject){
setTimeout(() => resolve('두번째 쿼리 with' + result1), 3000);
});
let result2 = await promise2;
console.log(result2); // 두번째 쿼리 with 첫번째 쿼리
// promise 객체 한개당 => query 하나
let promise3 = new Promise(function(resolve, reject){
setTimeout(() => resolve('세번째 쿼리 with' + result2), 3000);
});
let result3 = await promise3;
console.log(result3); // 세번째 쿼리 with 두번째 쿼리 with 첫번째 쿼리
}
f();
: mysql에서는 쿼리를 promise객체로 제공할 수 있음 → 따로 감싸지 않아도 감싸지게 할 수 있음
// mariadb.js
// mysql 모듈 소환
const mariadb = require("mysql2/promise"); // promise로 감쌈
// DB와 연결 통로 생성
// 연결 통로를 생성하는데도 시간이 걸리지 않을까?
// 당연히 통신하는데시간이 걸림
// connection해야 쿼리를 칠 수 있는데, 그동안은 쿼리를 하나만 쳤으니깐 잘 몰랐음
// 이젠 쿼리문을 여러개 써야함
// connection도 promise 객체임 따라서 await를 붙여 사용할 수 있음
// async 안에서만 await 쓸 수 있다고 했는데 어떻게 가능? 화살표 함수를 이용해 async를 설정
// 해주고 return해서 모듈로 사용할 수 있게 바꿈
// DB와 연결 통로 생성
const connection = async () => {
const conn = await mariadb.createConnection({
host: "127.0.0.1",
user: "root",
password: "root",
database: "Bookshop",
dateStrings: true,
});
return conn;
}
module.exports = connection;
// OrderController.js
const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈
const order = async (req, res) => {
const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } =
req.body;
let delivery_id;
let order_id;
//(1) delivery에 Insert
let sql =
"INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)";
let values = [delivery.address, delivery.receiver, delivery.contact];
let [results] = await conn.query(sql, values, (err, results) => {
if (err) {
console.log(err);
return res.status(StatusCodes.BAD_REQUEST).end();
}
delivery_id = results.insertId;
console.log("results.insertId", results.insertId);
console.log("conn.query - delivery_id", delivery_id);
});
console.log(result);
: 그런데 conn.query가 먹히질 않음 / 모듈을 가져와서 사용하는 방법을 try해보자
// OrderController.js
// const conn = require("../mariadb"); // db 모듈
const { StatusCodes } = require("http-status-codes"); // status code 모듈
const mariadb = require("mysql2/promise");
const order = async (req, res) => {
const conn = await mariadb.createConnection({
host: "127.0.0.1",
user: "root",
password: "root",
database: "Bookshop",
dateStrings: true,
});
const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } =
req.body;
let delivery_id;
let order_id;
//(1) delivery에 Insert
let sql =
"INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)";
let values = [delivery.address, delivery.receiver, delivery.contact];
let [results] = await conn.query(sql, values);
console.log(results);
POSTMAN) POST + localhost:9999/orders +
{
"items" : [
{
"book_id" : 9,
"quantity" : 1
},{
"book_id" : 6,
"quantity" : 1
}
],
"delivery" : {
"address" : "광주시 북구",
"receiver" : "김광주",
"contact" : "010-7777-7777"
},
"firstBookTitle" : "book9",
"totalQuantity" : 2,
"totalPrice" : 40000,
"userId" : 1
}
insertId가 3으로 잘 들어간 것을 확인할 수 있음
🍎🍏 오늘의 느낀점 : 오늘은 드디어 promise, async & await을 배웠다. 사실 이전에 다른 온라인강의에서 asyn와 await, promise까지 강의를 들은적이 있었는데 그때는 오오,, 그렇구나 하고 대충 이해했었는데 오늘은 한번더 개념을 이해하고 또 적용해보니 확실히 이해했다..! 이제 이 비동기처리를 가지고 쿼리문들을 잘 처리하는 것들을 잘 배워야겠다:)