Async, Promise & AJAX
JavaScript ไม่รอฟังก์ชันบางประเภททำงานเสร็จ — โค้ดบรรทัดถัดไปทำงานต่อทันที ทำให้ลำดับผลลัพธ์ไม่เป็นไปตามที่เขียน
ปัญหาของ asynchronous
setTimeout(function () {
console.log(1);
}, 5000);
console.log(2);
// ผลลัพธ์: 2 ออกก่อน แล้ว 1 ตามมาอีก 5 วินาที
ตัวอย่าง 3 งานจากสไลด์
function taskOne() { setTimeout(function(){ console.log("this is task 1"); }, 500); }
function taskTwo() { console.log("this is task 2"); }
function taskThree() { setTimeout(function(){ console.log("this is task 3"); }, 1000); }
taskOne(); // รอ 500ms
taskTwo(); // ไม่รอ
taskThree(); // รอ 1000ms
ผลลัพธ์: task 2 → task 1 → task 3 (ไม่ใช่ 1, 2, 3 ตามที่เขียน)
นี่คือเหตุผลที่ต้องมี Promise และ async/await
ฟังก์ชันไหนเป็น asynchronous บ้าง
- ฟังก์ชันจับเวลา —
setTimeout,setInterval, delay - การขอข้อมูลไป server แบบ AJAX — ยิง request แล้วทำโค้ดบรรทัดถัดไปทันที ไม่รอ response
- การอ่าน/เขียนไฟล์ (ฝั่ง NodeJS)
Promise
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("สำเร็จ"); // เรียก resolve เมื่อทำงานเสร็จ
// reject("ล้มเหลว"); // เรียก reject เมื่อผิดพลาด
}, 200);
});
myPromise
.then(result => console.log(result))
.catch(error => console.error(error));
| สถานะของ Promise | ความหมาย |
|---|---|
| pending | กำลังทำงาน ยังไม่รู้ผล |
| fulfilled | สำเร็จ — เรียก resolve() แล้ว รับผลด้วย .then() |
| rejected | ล้มเหลว — เรียก reject() แล้ว รับผลด้วย .catch() |
async / await
ทำให้ฟังก์ชัน asynchronous ทำงานเรียงลำดับได้ตามต้องการ
async function taskOne() {
return new Promise((resolve) => {
setTimeout(function () {
console.log("this is task 1");
resolve(true);
}, 3000);
});
}
async function taskTwo() {
return new Promise(resolve => {
setTimeout(function () {
console.log("this is task 2");
resolve(true);
}, 2000);
});
}
async function test() {
await taskOne(); // รอให้เสร็จก่อน
await taskTwo(); // แล้วค่อยทำตัวถัดไป
}
test();
กฎที่ต้องจำ:
await ใช้ได้เฉพาะใน function ที่ประกาศว่า async เท่านั้น
และฟังก์ชันที่ await ต้องคืน Promiseresolve จะคืนค่าอะไรก็ได้ — ค่าที่ใส่ใน resolve() คือค่าที่ await หรือ .then() จะได้รับ
Promise.any (ES10)
const myPromise1 = new Promise((resolve, reject) => {
setTimeout(() => { resolve("queen"); }, 200);
});
const myPromise2 = new Promise((resolve, reject) => {
setTimeout(() => { reject(); }, 100);
});
Promise.any([myPromise1, myPromise2]).then((x) => {
console.log(x); // "queen" — เอาตัวที่ resolve สำเร็จเร็วที่สุด
});
// ถ้าล้มเหลวทุกตัว
const a = Promise.reject('error A');
const b = Promise.reject('error B');
Promise.any([a, b])
.then(result => console.log(result))
.catch(error => console.error('ทุกตัวล้มเหลว:', error));
ใช้ตอนไหน: เช่นมี cluster server หลายเครื่องที่ให้บริการเหมือนกัน
ยิงพร้อมกันแล้วเอาตัวที่ตอบเร็วสุดไปใช้งานต่อ
AJAX คืออะไร
Asynchronous JavaScript and XML = การร้องขอข้อมูลไปยัง server โดยไม่ต้อง refresh หน้าเว็บ
- ยิง request แบบ async → ทำโค้ด JS บรรทัดอื่นต่อได้เลย
- ต้องส่งฟังก์ชันที่จะทำงานตอนได้ response เข้าไปด้วย (callback)
- เปลี่ยนเฉพาะบางส่วนของหน้าเว็บที่ต้องการ
XMLHttpRequest
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true); // true = asynchronous
xhttp.send();
}
| readyState | ชื่อ | ความหมาย |
|---|---|---|
| 0 | UNSENT | สร้าง object แล้ว แต่ยังไม่เปิดการเชื่อมต่อ |
| 1 | OPENED | เรียก open() แล้ว ยังไม่ได้ send() |
| 2 | HEADERS_RECEIVED | เรียก send() แล้ว เริ่มรับ header |
| 3 | LOADING | กำลังรับข้อมูลจาก server |
| 4 | DONE | เสร็จสมบูรณ์ — ใช้คู่กับ status == 200 |
// ส่งแบบ GET / POST
xhttp.open("GET", "demo_get.asp", true);
xhttp.send();
xhttp.open("POST", "demo_post.asp", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("fname=Henry&lname=Ford");
ปัจจุบันนิยมใช้ fetch() แทน XMLHttpRequest เพราะรองรับ Promise
และ async/await ได้เลย