[프로그래머스] Node기반 REST API 구현(9)

Lina Hongbi Ko·2024년 10월 14일
0

Programmers_BootCamp

목록 보기
34/76
post-thumbnail

2024년 10월 14일

✏️ Node.js 비동기

: Node.js는 논블로킹 I/O 방식임

  • 비동기 발생 : 일단 이전 시간이 오래 걸리면 기다려주지않고(알아서 하라고 하고) 다음 코드를 무작정 실행함

    ex) setTimeOut(), setInterval(), query(), …

    이것은 실행되는 코드가 기다려야 하는 시간이 생긴다는 의미

    → 쿼리를 쳐서 데이터베이스에 쿼리를 실행되는데 기다리는 시간이 필요함 (그런데 노드는 쿼리를 기다려주지 않고 그대로 다음코드가 실행됨)

    • 그런데 우린 쿼리문이 실행되어야 다음 코드들을 에러없이 실행할 수 있음
  • 비동기 처리

    • 비동기가 필요 없을 때가 있음(쿼리문) → 이전 코드들의 시간을 다 기다려주고, 순서를 맞춰서 코드를 실행해주겠다!
      1. 콜백 함수 : 할 일 다 하고, 이거 실행해줘(= 순서 맞춰서 이걸 뒤에 실행해달라고)
      2. promise 객체 사용(resolve, reject)
      3. then & catch
      4. ES2017 promise ⇒ async & await

✏️ Promise

💡 What's Prmoise

: 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(에러)
});

💡 then()

// 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 chaining

// 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

💡 async 첫번째 기능

// 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)
	}
);

💡 async 두번째 기능 & await

// 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();
// 함수호출 잊지 말아야함!!

💡 async 엮어쓰기

// 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();

✏️ bookshop_order에 적용

💡 비동기처리 시작 1

: 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);

💡 비동기처리 시작 2

: 그런데 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까지 강의를 들은적이 있었는데 그때는 오오,, 그렇구나 하고 대충 이해했었는데 오늘은 한번더 개념을 이해하고 또 적용해보니 확실히 이해했다..! 이제 이 비동기처리를 가지고 쿼리문들을 잘 처리하는 것들을 잘 배워야겠다:)

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글