본문 바로가기
경일/nodejs

[nodejs] todoApp async await 으로 조지기

by dev_kong 2022. 2. 4.
728x90
728x90

0. 목차

1. 개요

2. 프로미스 인스턴스 객체를 리턴하는 함수 만들기

3. 적용

4. 후기

1. 개요

https://kong-dev.tistory.com/127

 

[nodejs] todoApp 만들기 feat. mySQL

0. 목차 1. 개요 2. 기본세팅 3. CRUD 4. 후기 1. 개요 https://kong-dev.tistory.com/122 [nodejs]todoApp 만들기(express, nunjucks, mongodb,body-parser) 0. 목차 1. 개요 2. 기본세팅 3. HTML & CSS 4. CRUD..

kong-dev.tistory.com

ㅎ.. 하도 돌려써서 이젠 너덜너덜해진 나의 todoApp...

 

위 포스팅 맨 마지막에 보면 만든걸 async/await으로 조지고 싶다고 했었는데,

문제는 mysql 은 프로미스를 리턴하지 않기 때문에

async / await 사용이 불가능하다.

 

이런 경우에는 직접 프로미스 인스턴스 객체를 만들어서 사용이 가능하다.

 

const express = require('express');
const nunjucks = require('nunjucks');
const bodyParser = require('body-parser');
const mysql = require('mysql');

const db = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '비밀번호',
  database: 'todo_db',
});

db.connect();

const app = express();

app.set('view engine', 'html');
nunjucks.configure('views', { express: app });

app.use(bodyParser.urlencoded({ extended: true }));

app.use(express.static(`${__dirname}/public`));

app.get('/', (req, res) => {
  res.render('home.html');
});

app.get('/write', (req, res) => {
  res.render('write.html');
});

app.post('/create', async (req, res) => {
  db.query(
    `INSERT INTO todo(title, dueDate) VALUES('${req.body.todo}', '${req.body.dueDate}')`,
    (error, result) => {
      if (error) console.log(error);

      res.redirect('http://localhost:8000/list');
    }
  );
});

app.get('/list', (req, res) => {
  db.query(`SELECT * FROM todo`, (error, result) => {
    if (error) return console.log(error);

    res.render('list.html', { postList: result });
  });
});

app.post('/delete', (req, res) => {
  db.query(`DELETE FROM todo WHERE _id='${req.body._id}'`, (error, result) => {
    if (error) return console.log(error);

    res.redirect('http://localhost:8000/list');
  });
});

app.get('/edit/:id', (req, res) => {
  const _id = Number(req.params.id);

  db.query(`SELECT * FROM todo WHERE _id='${_id}'`, (error, result) => {
    if (error) return console.log(error);

    console.log(result);
    res.render('edit.html', { udtPost: result });
  });
});

app.post('/edit', (req, res) => {
  const todo = req.body.todo;
  const dueDate = req.body.dueDate;
  const _id = Number(req.body._id);

  db.query(
    `UPDATE todo 
    SET title = '${todo}', dueDate = '${dueDate}' 
    WHERE _id = '${_id}'`,
    (error, result) => {
      if (error) return console.log(error);

      res.redirect('http://localhost:8000/list');
    }
  );
});

app.listen(8000);

생각 해보니까 코드를 통째로 올리진 않았던거 같음.

일단 코드를 쭉 보면 막 그렇게 지저분해 보이진 않는다.

내용이 적기 때문이지.

사실 이정도 코드는 읽는데 문제가 없지만,

async / await 을 연습한다생각하고 해보면 좋을 듯하다.

 

2. 프로미스 인스턴스 객체를 리턴하는 함수 만들기

 

app.post('/create', (req, res) => {
  db.query(
    `INSERT INTO todo(title, dueDate) VALUES('${req.body.todo}', '${req.body.dueDate}')`,
    (error, result) => {
      if (error) console.log(error);

      res.redirect('http://localhost:8000/list');
    }
  );
});

그냥 create 부분 떼왔음

 

이정도 코드는 사실 읽기가 어렵지 않다.

 

/create 에 post 요청이 들어오면,

콜백함수가 실행된다.

콜백함수 내부에서 db.query method가 작동하고,

데이터베이서로 쿼리문을 날린다.

쿼리문을 날리고 에러가 발생하면 에러 메세지를 띄우고

에러가 없으면 res.redirect 가 실행된다.

 

아주 간단함.

그래도 굳이굳이 이걸 나는 async / await 구문으로 조지고 싶은데,

할 수가 없다. 

저저 db.query method가 프로미스 객체를 리턴하지 않기 때문임.

그렇다면 우린 프로미스 객체를 리턴하는 함수를 하나만들고 

new Promise 의 인수로 전달될 콜백펑션 안에 

dbquery를 집어 넣고,

dbquery의 콜백함수의 인수인 result를 resolve 로 전달하고

error를 reject로 전달하면 된다.

 

ㅎㅎ...

 

코드... 코드를 보자..!

 

function dbQueryAsync(query) {
  return new Promise((resolve, reject) => {
    db.query(query, (error, result) => {
      if (error) {
        reject(error);
      }
      resolve(result);
    });
  });
}

짜자안.

우선 함수 이름을 dbQueryAsync라고 이쁘게 지었음

이름 잘 지은거 같아서 기분좋다.

 

그리고 이름이 이쁜 dbQueryAsync 함수는 query라는 인수를 전달받아서 프로미스 인스턴스를 리턴한다.

그리고 Promise 생성자함수의 인수로 전달된 콜백펑션에

db.query method를 박아넣고, 

dbQueryAsync 함수의 인수인 query 를 그대로 전달 받아서

db.query의 첫번째 인수로 사용한다.

그리고 두번째 인수인 콜백함수는

실행 결과를 처리하는 함수인데,

첫번째 인수로는 실패했을때의 에러를

두번째 인수는 성공했을 때의 결과를 나타낸다.

그러니까 실패하면 에러가 생기는데 에러가 생기면

에러의 내용을 reject로 전달하고,

에러 없으면 성공 결과를 resolve 로 전달한다.

 

ㅎ.. 이것도 무슨 말인가 싶으면 

코드.. 코드를 보자..!

3. 적용

 

function dbQueryAsync(query) {
  return new Promise((resolve, reject) => {
    db.query(query, (error, result) => {
      if (error) {
        reject(error);
      }
      resolve(result);
    });
  });
}

app.post('/create', async (req, res) => {
  try {
    await dbQueryAsync(
      `INSERT INTO todo(title, dueDate) VALUES('${req.body.todo}', '${req.body.dueDate}')`
    );
    res.redirect('http://localhost:8000/list');
  } catch (error) {
    console.log(error);
  }
});

 

음음..! 위에 설명한걸 그대로 코드로 만든거임

dbQueryAsync 의 인수로 쿼리문을 실행하면,

프로미스 객체 안의 db.query method 가 쿼리문을 받아서 동작하고,

결과 또는 에러내용을 각각 resolve, reject 를 통해 전달한다.

(여기선 굳이 결과값을 받아서 사용할 일이 없어서 변수에 담지 않았음)

 

이런식으로 전체 코드를 다 변경을 해보면

 

const express = require('express');
const nunjucks = require('nunjucks');
const bodyParser = require('body-parser');
const mysql = require('mysql');

const db = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'Hun71033498!',
  database: 'todo_db',
});

db.connect();

const app = express();

app.set('view engine', 'html');
nunjucks.configure('views', { express: app });

app.use(bodyParser.urlencoded({ extended: true }));

app.use(express.static(`${__dirname}/public`));

function dbQueryAsync(query) {
  return new Promise((resolve, reject) => {
    db.query(query, (error, result) => {
      if (error) {
        reject(error);
      }
      resolve(result);
    });
  });
}

app.get('/', (req, res) => {
  res.render('home.html');
});

app.get('/write', (req, res) => {
  res.render('write.html');
});

app.post('/create', async (req, res) => {
  try {
    await dbQueryAsync(
      `INSERT INTO todo(title, dueDate) VALUES('${req.body.todo}', '${req.body.dueDate}')`
    );
    res.redirect('http://localhost:8000/list');
  } catch (error) {
    console.log(error);
  }
});

app.get('/list', async (req, res) => {
  try {
    const postList = await dbQueryAsync(`SELECT * FROM todo`);
    res.render('list.html', { postList });
  } catch (error) {
    console.log(error);
  }
});

app.post('/delete', async (req, res) => {
  try {
    await dbQueryAsync(`DELETE FROM todo WHERE _id='${req.body._id}'`);
    res.redirect('http://localhost:8000/list');
  } catch (error) {
    console.log(error);
  }
});

app.get('/edit/:id', async (req, res) => {
  try {
    const _id = Number(req.params.id);

    const udtPost = await dbQueryAsync(`SELECT * FROM todo WHERE _id='${_id}'`);
    res.render('edit.html', { udtPost });
  } catch (error) {
    console.log(error);
  }
});

app.post('/edit', async (req, res) => {
  try {
    const todo = req.body.todo;
    const dueDate = req.body.dueDate;
    const _id = Number(req.body._id);

    await dbQueryAsync(`UPDATE todo 
    SET title = '${todo}', dueDate = '${dueDate}' 
    WHERE _id = '${_id}'`);

    res.redirect('http://localhost:8000/list');
  } catch (error) {
    console.log(error);
  }
});


app.listen(8000);

 

이렇게 전부 변경했다.

 

콜백으로 처리했을때 보다 깔끔해진 모습이다.

4. 후기

 

처음엔 막막했는데,

찬찬히 생각해보니 이해가되고

만들어지더라,

코드들은 전부 async await 구문으로 바꾸고나서,

작동시켜보니 

콜백으로 짰던 코드와 같이

잘 작동이 되는걸 확인햇을 땐 기분이 매우 좋았음 ㅎㅎ

 

728x90
728x90

댓글