ตัวอย่างการใช้ Promise Async Await ใน NodeJs + MySql เพื่อแก้ปัญหา callback hell

สำหรับ Javascript นั้น การทำงานที่เป็น asynchronous เช่น การอ่านข้อมูลจาก MySQL ใน NodeJS เวลาเรารันคำสั่ง SQL ระบบจะรัน คำสั่ง javascript ถัดไปทันที โดยไม่รอให้ MySQL ส่งข้อมูลกลับมาก่อนดังนี้

console.log("1");

mysql_connection.connect(()=>{
           
            mysql_connection.query(sql,place_holder,(err,result)=>{
        
                console.log("2");
        
            });
        

}); 

console.log("3");

ผลลัพธ์ที่ได้คือ 

1

3

2

เพราะ javascript จะรันคำสั่ง  console.log("3"); เลยโดยไม่รอผลลัพธ์ของ

หากเราจำเป็นต้องรันคำสั่ง SQL 2 ครั้ง โดยต้องรอผลจากคำสั่ง SQL แรกต้อทำดังนี้

mysql_connection.connect(()=>{

            mysql_connection.query(sql,place_holder,(err,result)=>{

                        ......   

                        ......

                        ......
                         mysql_connection.query(sql2,place_holder,(err,result2)=>{
        
                        
                        });
            });

});

หากมีคำสั่ง SQL ที่ต้องรอผลจาก คำสั่ง SQL ก่อนหน้าเยอะขึ้น จะนำมาซึ่งปัญหา callback hell ซึ่งสามารถ แก้ได้ด้วย การใช้คำสั่ง Promise Async Await ดังตัวอย่างต่อไปนี้

https://github.com/nuntawa/nodejs_mysql_promise_async_await

รับเขียนโปรแกรม NodeJS + MySQL

 1. สร้าง NodeJS Project โดย เปิด Command Line และ พิมพ์ md node_mysql เพื่อสร้าง folder พิมพ์ cd node_mysql เพื่อเข้าไปที่ folder และ พิมพ์ npm init -y เพื่อ สร้างไฟล์ package.json


 

2. install express module และ mysql module

โดย พิมพ์ npm install express --save และ npm install mysql --save


 3. เปิด VS Code โดยพิมพ์ code .

 

โครงสร้าง Database ที่เตรียมไว้คือ

ตาราง product เก็บข้อมูลสินค้า

ตาราง part เก็บอะไหล่ของสินค้า มี unit_count_id เป็น foreign key สำหรับระบุว่า สินค้านี้ใช่หน่วยอะไร

ตาราง unit_count เก็บหน่วยนับ

ตาราง product_part  เก็บว่าสินค้าใช้อะไหล่อะไรบ้างจำนวนเท่าไหร่


4. สร้างไฟล์ index.js แล้วพิมพ์ Code ใน visual studio
( Code ดูได้จาก https://github.com/nuntawa/nodejs_mysql_promise_async_await )

var express=require('express');
var app=express();
var port=process.env.PORT || 5000;
var mysql = require('mysql');

//กำหนด Host และ Username Password ของ MySQL
var mysql_connection = mysql.createConnection
    host: "localhost",
    user: "root",
    password: "",
    database: "factory"
});
//สร้าง Function สำหรับ เชื่อมต่อ MySQL โดย รับค่าคำสั่ง sql  และค่าของตัวแปรอยู่ใน place_holder ( เพื่อป้องกัน SQL Injection )
var get_mysql_data=(sql,place_holder)=>
{
    //กำหนดให้ return  object Promise รอ
    return new Promise(function(resolve, reject){

        mysql_connection.connect(()=>{
            //รันคำสั่ง SQL
            mysql_connection.query(sql,place_holder,(err,result)=>{
        
                if(err)
                {
                    console.log(err);
                    return reject(err);
                }
        
                if(result==null)
                {
                    return reject({message:"Mysql Error"});
                }
                //ส่งผลลัพธืของคำสั่ง sql กลับไปให้ทำงานต่อ
                resolve(result);
        
            })
        
        });

    });
}

//กำหนด Route
app.get('/', async (req, res)=>{
    
    var product;
    try{
        //ให้รอผลจากคำสั่ง SQL SELECT * FROM product ก่อนค่อยทำงานในคำสั่งถัดไป ( ทำงานแบบ synchronous  )
        product= await get_mysql_data("SELECT * FROM product");

    }catch(err)
    {
        console.log(err);
    }
    //เมื่อได้ข้อมูลในตาราง Product แล้วเราจะเอามา part  ของแต่ละ product
    for(var i=0;i<product.length;i++)
    {
        try{

            var sql=`SELECT part_name,product_part.qty,unit_count_name FROM
            part INNER JOIN product_part ON part.part_id=product_part.part_id
            INNER JOIN unit_count ON unit_count.unit_count_id=part.unit_count_id
            WHERE (product_id=?)`;
            
            var part= await get_mysql_data(sql,[product[i].product_id]);
            product[i]["part"]=part;

        }
        catch(err)
        {
            console.log(err);
        }
        
    }
    var html="";
    for(var i=0;i<product.length;i++)
    {  //แสดงชื่อ product
        html+="<h4>"+product[i].product_name+"<h4>";
        html+="<ul>";
        product[i].part.forEach(part_item => {
            //แสดง part และจำนวนที่ใช้ของแต่ละ product
            html+="<li>"+part_item.part_name+" จำนวน "+part_item.qty+" "+part_item.unit_count_name+"</li>";
            
        });
        html+="</ul>";

        html+="<hr />";
    }
    res.send(html);
});

//กรณีไม่พบหน้า
app.get('*', (req, res)=>{
    res.status(404).send('Page Not Found');
});

app.listen(port);
console.log("server start");

ไปที่ ComandLine และพิมพ์ node index ผลลัพธ์ที่ได้คือ