Sam Baek, The Dev's Corner

๐Ÿ”— Node Promise Async [5ํŽธ]

25 Jul 2023

Promise Async


์•ž์„œ Promise์™€ Async๋Š” ํฌ์ŠคํŒ…ํ•œ ์ ์ด ์žˆ์œผ๋‹ˆ
์ž์„ธํ•œ ์„ค๋ช…์€ ์ƒ๋žตํ•˜๊ณ  4ํŽธ์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด
๋ฌธ์ œ์ ์ด ํ•˜๋‚˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” mysql์—์„œ requset(SQL๋ฌธ)๋ฅผ ์ „๋‹ฌํ•˜๊ณ 
SQL๋ฌธ์„ ๋ฐ›๋Š” ๋™์•ˆ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ์˜ ์‹œ๊ฐ„์„ Promise๋กœ ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ
๊ทธ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ return๊ฐ’์„ ํ•จ์ˆ˜๊ฐ€ ์ œ๋Œ€๋กœ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
์—ฌ๊ธฐ์„œ Promise๋กœ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๋Š” ๋ง์ด ๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด
์ฝœ๋ฐฑํ•จ์ˆ˜์ฒ˜๋ฆฌํ–ˆ๋‹ค๋Š” ๋ง์ด๋‹ค. funcion(err,req,fields){}; ์ด ๋ถ€๋ถ„!
ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ทธ ์•ˆ์— pool.query๋ฅผ ํ†ตํ•ด SQL๋ฌธ์„ ์š”์ฒญํ•˜๊ณ ,
๋ฐ”๋กœ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋‚˜์˜ค๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๋Š” ๋ง์ด๋‹ค.

๋ฌธ์ œ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋  ๋•Œ๊นŒ์ง€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค๋Š” ๊ฒƒ์ธ๋ฐ
์™œ ๋ฌธ์ œ๋ƒ๋ฉด pool.query๋ฌธ ๋’ค๋กœ console.log(โ€œvlavlaโ€)๊ฐ€ ์žˆ์–ด๋„
console.log๊ฐ€ ๋จผ์ € ๋‚˜์˜ค๊ณ  ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์šฐ๋ฆฌ๋Š” ์›ํ•˜๋Š” ๋•Œ์— ์›ํ•˜๋Š”๊ฒŒ ๋™์ž‘๋˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋ก  Promise๋กœ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋“ ์ง€
Async/Await์„ ์จ์„œ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

JavaScript์˜ ๋™์ž‘๊ณผ์ •์€ CALL STACK๊ณผ
MICROTASK QUEUE, MACROTASK QUEUE๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ
MICROTASK QUEUE๊ฐ€ ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๊ณ 
MACROTASK QUEUE๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค.
๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ mysql ํ•จ์ˆ˜๋Š” MICROTASK QUEUE ์—ฌ๊ธฐ ํ•ด๋‹นํ•œ๋‹ค.
๋ฌธ์ œ๋Š” console๊ฐ™์€ ๊ฒฝ์šฐ๋Š” CALL STACK์— ํ•ด๋‹น๋ผ ๋ฐ”๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
CALL STACK์ด 0์ˆœ์œ„, MICROTASK QUEUE๊ฐ€ 1์ˆœ์œ„,
MACROTASK QUEUE๊ฐ€ 2์ˆœ์œ„์ธ์…ˆ์ด๊ณ 
๊ฒฐ๊ตญ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ ์žํ•˜๋Š” ๊ฒƒ์€ ์ฝœ์Šคํƒ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด
Promise๋‚˜ Async/Await์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ธฐ์กด ๋ฌธ๋ฒ•์˜ ์ˆ˜์ •


Async/Await์„ ์“ฐ์ง€ ์•Š์„ ๋•Œ์™€ ์‚ฌ์šฉํ•  ๋•Œ์˜ ๋ฌธ๋ฒ• ์ฐจ์ด๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

Before

const pool = mysql.createPool({
    host: "",
    user: "admin",
    password: "",
    port: 3306,
    database: "db_name",
  });
function getNotes(){
    pool.query(`select BIN_TO_UUID(uuid,true) as uuid,title,contents,created from notes);`, function (err, results, fields) {
    console.log(results);
    });
};

After

const pool = mysql.createPool({
    host: "",
    user: "admin",
    password: "",
    port: 3306,
    database: "db_name",
  })
  .promise();

export async function getNotes(){
    const [rows] = awit pool.query(`select BIN_TO_UUID(uuid,true) as uuid,title,contents,created from notes);`);
    return rows
};

DB์— ๋Œ€ํ•œ ํ’€ ์ฟผ๋ฆฌ๋ฅผ ์ •๋ฆฌํ–ˆ๋‹ค๋ฉด,
index๋‚˜ db ํ’€ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์žํ•˜๋Š” ์œ„์น˜๊ฐ€ ์žˆ์„ ๊ฒƒ ์•„๋‹Œ๊ฐ€
๊ทธ ๊ณณ์— module๋กœ ํ•ด๋‹น ์ฟผ๋ฆฌ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ 
์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

import express from "express";
import { getNotesAsync, getNoteAsync, addNotesAsync, updateNoteAsync, deleteNoteAsync } from "./database2.js";

const app = express()
const port = 3000

// body ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฏธ๋“ค์›จ์–ด ์„ค์ •
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.get('/notes', async (req, res) => {
  const result = await getNotesAsync();
  res.send(result);
});

app.get('/note/:id', async (req, res, next) => {
  try{
    const id = req.params.id;
    if(!id) throw new Error('400@No Path Parameter');
    const result = await getNoteAsync(id);
    if(!result) res.send({});
    if(result.length === 0) res.send({});
    res.send(result[0]);
  }
  catch(err){
    next(err);
  }
});

app.get('/notes', async (req, res, next) => {
  const body = req.body;
  if(!body.title) sendStatus(400);
  if(!body.contents) sendStatus(400);
  const result = await addNotesAsync(body.title, body.contents);
  if(typeof result.affectedRows === "undefined") throw new Error(`400@Not created`);
  if(typeof result.affectedRows !== 1) throw new Error(`400@Not created`);
  res.sendStatus(201);
});

app.use((err, req, res, next) => {
  console.log(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
});

body์ฒ˜๋ฆฌ


POST๋ฅผ ๋งŒ๋“ค ๋•Œ, body๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
Express ๊ณต์‹๋ฌธ์„œ๋Š” ์ด๋ฅผ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋ผ๊ณ ํ•œ๋‹ค.

app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded

์—๋Ÿฌ์ฒ˜๋ฆฌ


Express ๊ณต์‹๋ฌธ์„œ์— ์—๋Ÿฌ ํ•ธ๋“ค๋ง์— ๋Œ€ํ•œ ๋ถ€๋ถ„๋„ ์ฐธ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ
์•„๋ž˜์ฒ˜๋Ÿผ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉํ•˜๋ผ ๋ช…์‹œํ•œ๋‹ค.

app.use((err, req, res, next) => {
  console.log(err.stack);
  res.status(500).send('Something broke!');
});