JavaScript Callback , Promise , Async / Await

ลำดับการทำงานใน JavaScript จะแบบออกเป็น 2 ลักาณะ
1.Non-Blockin หรือ อะซิงโครนัส Asynchronous
คือการทำงานแบบไม่พร้อมกัน หรือไม่ต่อเนื่องกัน โดยงานบางส่วนที่ต้องใช้เวลา หรือมีการหน่วงเวลา งานส่วนนี้จะถูกทำงานในเบื้องหลัง ส่วนงานอื่นที่ไม่ต้องรอเวลา หรือไม่ได้ถูกหน่วงเวลาไว้ จะสามารถทำงานล่วงหน้าไปก่อนได้เลย

ตัวอย่างคำสั่ง

  • setTimeout
  • setInterval
  • Promise

2.Blocking หรือ Synchronous
คือเป็นการทำงานที่ทำตามลำดับ มีการหยุดรอให้ส่วนแรกดำเนินการเสร็จก่อน จึงจะทำงานในลำดับต่อไป

ตัวอย่างคำสั่ง

  • comfirm

ตัวอย่าง ปัญหาที่เจอ ของการทำงานแบบ asynchronous

console.log("เริ่มต้นโหลด")
console.log("กำลังทำงาน")
console.log("จบการทำงาน")
เริ่มต้นโหลด
กำลังทำงาน
จบการทำงาน

เมื่อมีการ setTimeout ทำให้ลำดับการทำงาน ไม่ถูกต้อง

console.log("เริ่มต้นโหลด")
setTimeout(()=>{
    console.log("กำลังทำงาน")
},3000)
console.log("จบการทำงาน")
เริ่มต้นโหลด
จบการทำงาน
กำลังทำงาน

Callback function

แบบปกติ ที่ยังไม่ได้ setTimeout

function calculate(x, y) {
  return x + y
}
function display(result) {
  console.log(`ผลบวก ${result}`);
}
const sum = calculate(100,50)
display (sum)
ผลบวก 150

แบบ setTimeout ทำให้ได้ผลลัพธ์ที่ไม่ถูกต้อง display() ทำงานก่อน โดยไม่ calculate() ที่มีการ  setTimeout  ไว้

function calculate(x, y) {
  setTimeout(() => {
    console.log("กำลังคำนวณ......");
    return x + y
  }, 3000)

}
function display(result) {
  console.log(`ผลบวก ${result}`);
}
const sum = calculate(100, 50)
display(sum)
ผลบวก undefined
กำลังคำนวณ......

การแก้ปัญหาด้วย callback function

function calculate(x, y,callback) {
  console.log("กำลังคำนวณ......");
  setTimeout(() => {
    const sum = x + y
    callback(sum)
  }, 3000)

}
function display(result) {
  console.log(`ผลบวก ${result}`);
}
const sum = calculate(100, 50,display)
กำลังคำนวณ......
ผลบวก 150

เขียนแบบลดรูปลงไปอีกแบบ

function calculate(x, y,callback) {
  console.log("กำลังคำนวณ......");
  setTimeout(() => {
    const sum = x + y
    callback(sum)
  }, 3000)

}

calculate(100, 50,function(result){
  console.log(`ผลบวก ${result}`);
})

และอีกแบบ

function calculate(x, y,callback) {
  console.log("กำลังคำนวณ......");
  setTimeout(() => {
    const sum = x + y
    callback(sum)
  }, 3000)

}

calculate(100, 50,(result)=>{
  console.log(`ผลบวก ${result}`);
})

การเขียนแบบปกติ

const url1 = "kong.dev/file1.json"
function dowloading(url) {
  console.log(`กำลังดาวโหลด ${url}`)
}

function complete() {
  console.log("ดาวโหลดเรียบร้อย!");
}
dowloading(url1)
complete()
กำลังดาวโหลด kong.dev/file1.json
ดาวโหลดเรียบร้อย!

การทำงานเมื่อมีการ setTimeout ผลที่ได้คืองานไม่ถูกต้องตามลำดับ

const url1 = "kong.dev/file1.json"
function dowloading(url) {
  setTimeout(() => {
    console.log(`กำลังดาวโหลด ${url}`)
      , 3000
  })
}

function complete() {
  console.log("ดาวโหลดเรียบร้อย!");
}
dowloading(url1)
complete()
ดาวโหลดเรียบร้อย!
กำลังดาวโหลด kong.dev/file1.json

แก้ไขด้วยการใช้ callback

const url1 = "kong.dev/file1.json"
function dowloading(url,callback) {
  console.log(`กำลังดาวโหลด ${url}`)
  setTimeout(() => {
    callback()
  }, 3000)
}

dowloading(url1,()=>{
  console.log("ดาวโหลดเรียบร้อย!");
})
กำลังดาวโหลด kong.dev/file1.json
ดาวโหลดเรียบร้อย!

และอีกแบบ กรณีต้องการส่งต่อค่าเข้าไปใน callback ด้วย

const url1 = "kong.dev/file1.json"
function dowloading(url, callback) {
  console.log(`กำลังดาวโหลด ${url}`)
  setTimeout(() => {
    callback(url)
  }, 3000)
}

function complete(result) {
  console.log(`ดาวโหลด ${result} เรียบร้อย!`)
}

dowloading(url1, complete)
กำลังดาวโหลด kong.dev/file1.json
ดาวโหลด kong.dev/file1.json เรียบร้อย!

หรือเขียนอีกแบบ ลดรูปลงไป

const url1 = "kong.dev/file1.json"
function dowloading(url, callback) {
  console.log(`กำลังดาวโหลด ${url}`)
  setTimeout(() => {
    callback(url)
  }, 3000)
}

dowloading(url1, (result)=>{
  console.log(`ดาวโหลด ${result} เรียบร้อย!`)
})
กำลังดาวโหลด kong.dev/file1.json
ดาวโหลด kong.dev/file1.json เรียบร้อย!

ตัวอย่าง เมื่อต้องทำงานมากกว่า 1ขั้นตอน
การใช้ Callback แบบนี้ทำให้โค้ดดูยาก และถูกเรียกว่า Callback Hell

const url1 = "kong.dev/file1.json"
const url2 = "kong.dev/file2.json"
const url3 = "kong.dev/file3.json"
function dowloading(url, callback) {
  console.log(`กำลังดาวโหลด ${url}`)
  setTimeout(() => {
    callback(url)
  }, 3000)
}

dowloading(url1, (result) => {
  console.log(`ดาวโหลด ${result} เรียบร้อย!`)
  dowloading(url2, (result) => {
    console.log(`ดาวโหลด ${result} เรียบร้อย!`)
    dowloading(url3, (resutl) => {
      console.log(`ดาวโหลด ${result} เรียบร้อย!`)
    })
  })
})
กำลังดาวโหลด kong.dev/file1.json
ดาวโหลด kong.dev/file1.json เรียบร้อย!
กำลังดาวโหลด kong.dev/file2.json
ดาวโหลด kong.dev/file2.json เรียบร้อย!
กำลังดาวโหลด kong.dev/file3.json
ดาวโหลด kong.dev/file2.json เรียบร้อย!

Promise (พรอมิส)
ถูกนำมาใช้งานแบบ Asynchronous คือ ให้รอในระหว่างที่ผลลัพธ์ยังไม่เกิดขึ้น ใช้กับงานที่มีการหน่วงเวลา และแก้ปัญหา Callback hell
การสร้าง Promise

Promise(function (resolve, reject) {
  
})

CallBack Function – ใช้กำหนดการกระทำบางอย่าง
การทำงานใน Promise จะมี 3 สถานะ pending, resolve, reject

  • pending : เป็นสถานะเริ่มต้อนของ Promise
    ถ้าทำงานสำเร็จจะเป็น resolve
    ถ้าล้มเหลวจะเป็น reject
  • resolve/fulfilled : เป็นพารามิเตอร์ของ callback ซึ่งใช้กำหนดสถานะหากทำงาน “สำเร็จ”
  • reject : เป็นพารามิเตอร์ของ callback ซึ่งใช้กำหนดสถานะหากทำงาน “ผิดพลาด”
let connect = true
const dowloading = new Promise(function (resolve, reject) {
  if (connect) {
    resolve("ดาวน์โหลดเสร็จเรียบร้อย")
  } else {
    reject("เกิดข้อผิดพลาดระหว่าง Download")
  }
})

ตัวอย่างการใช้งานกับ setTimeout

let connect = true
const dowloading = new Promise(function (resolve, reject) {
  setTimeout(() => {
    if (connect) {
      resolve("ดาวน์โหลดเสร็จเรียบร้อย")
    } else {
      reject("เกิดข้อผิดพลาดระหว่าง Download")
    }
  },3000)
})

เมธอด then(), catch(), finally()
การทำงานของ Promise ระหว่างที่ตรวจสอบสถานะของ Promise อยู่ว่าเป็น resolve หรือ reject สามารถกำหนดขั้นตอนต่อไปในการทำงานได้โดยอาศัย then(), catch() มาใช้ตอบสถานะดังกล่าว

  • then() : ใช้งานร่วมกับสถานะ resolve หรือเมื่อ Promise ทำงานสำเร็จ
  • catch() : ใช้งานร่วมกับสถานะ reject หรือเมื่อ Promise ทำงานผิดพลาด
  • finally() : ไม่ว่าผลลัพธ์ของสถานะจะเปนอย่างไร ให้ทำงานต่อส่วนนี้ได้เลย
let connect = true
const dowloading = new Promise(function (resolve, reject) {
  //
})

dowloading.then(result=>{
  //
})

dowloading.catch(result=>{
  //
})

หรือแบบลดรูป ต่อท้าย

let connect = true
const dowloading = new Promise(function (resolve, reject) {
  //
}).then(result=>{
  //
}).catch(result=>{
  //
})

ตัวอย่าง

const connect = true
const url1 = "kong.dev/file1.json"

function dowloading(url) {
  return new Promise(function (resolve, reject) {
    console.log(`กำลังโหลด ${url}........`);
    setTimeout(() => {
      if (connect) {
        resolve(`โหลด ${url} เรียบร้อย`);
      } else {
        reject('เกิดข้อผิดพลาด');
      }
    }, 3000)
  })
}

dowloading(url1).then(result => {
  console.log(result);
}).catch(err => {
  console.log(err);
}).finally(() => {
  console.log('จลการทำงาน');
})
connect = true
กำลังโหลด kong.dev/file1.json........
โหลด kong.dev/file1.json เรียบร้อย
จลการทำงาน

connect = false
กำลังโหลด kong.dev/file1.json........
เกิดข้อผิดพลาด
จลการทำงาน

 

ตัวอย่างการ then แบบที่ 1 : Promise Hell

const connect = true
const url1 = "kong.dev/file1.json"
const url2 = "kong.dev/file2.json"
const url3 = "kong.dev/file3.json"

function dowloading(url) {
  return new Promise(function (resolve, reject) {
    console.log(`กำลังโหลด ${url}........`);
    setTimeout(() => {
      if (connect) {
        resolve(`โหลด ${url} เรียบร้อย`);
      } else {
        reject('เกิดข้อผิดพลาด');
      }
    }, 3000)
  })
}

dowloading(url1).then(result => {
  console.log(result);
  dowloading(url2).then(result => {
    console.log(result);
    dowloading(url3).then(result => {
      console.log(result);
    })
  })
})
กำลังโหลด kong.dev/file1.json........
โหลด kong.dev/file1.json เรียบร้อย
กำลังโหลด kong.dev/file2.json........
โหลด kong.dev/file2.json เรียบร้อย
กำลังโหลด kong.dev/file3.json........
โหลด kong.dev/file3.json เรียบร้อย

ตัวอย่างการ then แบบที่ 2

const connect = true
const url1 = "kong.dev/file1.json"
const url2 = "kong.dev/file2.json"
const url3 = "kong.dev/file3.json"

function dowloading(url) {
  return new Promise(function (resolve, reject) {
    console.log(`กำลังโหลด ${url}........`);
    setTimeout(() => {
      if (connect) {
        resolve(`โหลด ${url} เรียบร้อย`);
      } else {
        reject('เกิดข้อผิดพลาด');
      }
    }, 3000)
  })
}

dowloading(url1).then((result)=>{
  console.log(result);
  return dowloading(url2)
}).then((result)=>{
  console.log(result);
  return dowloading(url3)
})
กำลังโหลด kong.dev/file1.json........
โหลด kong.dev/file1.json เรียบร้อย
กำลังโหลด kong.dev/file2.json........
โหลด kong.dev/file2.json เรียบร้อย
กำลังโหลด kong.dev/file3.json........

async await ใช้คู่กับ Promise

const connect = true
const url1 = "kong.dev/file1.json"
const url2 = "kong.dev/file2.json"
const url3 = "kong.dev/file3.json"

function dowloading(url) {
  return new Promise(function (resolve, reject) {
    console.log(`กำลังโหลด ${url}........`);
    setTimeout(() => {
      if (connect) {
        resolve(`โหลด ${url} เรียบร้อย`);
      } else {
        reject('เกิดข้อผิดพลาด');
      }
    }, 3000)
  })
}

async function start (){
  console.log(await dowloading(url1));
  console.log(await dowloading(url2));
  console.log(await dowloading(url3));
}

start ()
กำลังโหลด kong.dev/file1.json........
โหลด kong.dev/file1.json เรียบร้อย
กำลังโหลด kong.dev/file2.json........
โหลด kong.dev/file2.json เรียบร้อย
กำลังโหลด kong.dev/file3.json........
โหลด kong.dev/file3.json เรียบร้อย

 

สำหรับท่านที่สนใจ แนะนำเข้าไปดูคลิปสอบ ของท่าน KongRuksiam
ได้ตามลิ้งด้านล่างครับ อันนี้ผมแค่โน๊ตไว้กันลืมครับ

รู้จักกับ Callback , Promise , Async / Await | JavaScript จบในคลิปเดียว
KongRuksiam Official

Exit mobile version