บทนำ
ถ้าคุณเขียน JavaScript มาสักระยะแล้ว คงเคยสงสัยว่า JavaScript จัดการกับงานหลายอย่างพร้อมกันได้อย่างไร ทั้งที่เป็นภาษาแบบ single-threaded คำตอบของสิ่งนี้คือ Event Loop กลไกเบื้องหลังความสามารถ asynchronous ของ JavaScript ที่ทำให้เราสามารถใช้ setTimeout
, fetch
, Promise
และ async/await
ได้อย่างลื่นไหล
JavaScript เป็น Single-Threaded
JavaScript ดำเนินคำสั่งทีละบรรทัดใน Call Stack ซึ่งทำให้ดูเหมือนทำงานได้เพียงอย่างเดียวในแต่ละช่วงเวลา แต่เมื่อมีงานแบบ asynchronous เข้ามา JavaScript ต้องใช้ความช่วยเหลือจาก Web APIs และ Event Loop เพื่อจัดลำดับและควบคุมการทำงานให้ไม่บล็อกการประมวลผล
องค์ประกอบหลักของ Event Loop
- Call Stack: Stack สำหรับเรียกฟังก์ชันตามลำดับ
- Web APIs: ฟีเจอร์ที่ browser มอบให้สำหรับงาน async เช่น setTimeout, fetch
- Callback Queue (Task Queue): คิวที่เก็บ callback ที่รอเข้า Stack
- Event Loop: กลไกที่ตรวจสอบ Stack และ Queue อย่างต่อเนื่อง
ตัวอย่างเบื้องต้น
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
ผลลัพธ์:
1
3
2
แม้ว่า setTimeout ถูกตั้งเวลาเป็น 0 แต่ JavaScript จะรอจน Stack ว่างก่อนแล้วจึงนำ callback เข้าคิว
Microtask Queue คืออะไร?
JavaScript มีอีกคิวหนึ่งชื่อว่า Microtask Queue ซึ่งใช้สำหรับ Promise
และ async/await
โดยจะมีลำดับความสำคัญสูงกว่า Task Queue
console.log("A");
Promise.resolve().then(() => console.log("B"));
setTimeout(() => console.log("C"), 0);
console.log("D");
ผลลัพธ์คือ:
A
D
B
C
การทำงานของ async/await
async/await เป็น syntax ที่ใช้จัดการ promise ได้อย่างสะอาดเข้าใจง่าย แต่เบื้องหลังยังคงใช้ microtask queue
async function run() {
console.log("1");
await Promise.resolve();
console.log("2");
}
run();
console.log("3");
ผลลัพธ์:
1
3
2
คำสั่งหลัง await จะถูก queue ไปไว้ใน microtask queue
แผนภาพลำดับงาน
- Stack ทำงาน synchronous ปกติ
- เมื่อมี async function → ถูกส่งไปยัง Web APIs
- เมื่อเสร็จ → callback ถูกส่งไป Task หรือ Microtask Queue
- Event Loop ตรวจสอบ ถ้า Stack ว่าง → ดึง callback เข้า Stack
ข้อควรระวัง
- ไม่ควรมี loop ใหญ่ที่บล็อก stack เพราะจะทำให้ callback ค้าง
- microtask queue ไม่มีการจำกัดจำนวน ถ้าสร้าง promise แบบวนลูปอาจทำให้ browser ค้าง
- ระวัง callback hell ควรใช้ async/await หรือ compose function
สรุป
Event Loop เป็นกลไกที่ทำให้ JavaScript รองรับ asynchronous ได้อย่างมีประสิทธิภาพ การเข้าใจการทำงานของมันจะช่วยให้คุณเขียนโค้ดที่เข้าใจง่าย แก้บั๊กได้เร็ว และออกแบบระบบที่ responsive ต่อผู้ใช้
ใช้เวลาอ่าน: 10 – 15 นาที | เขียนโดย: ทีมงาน poolsawat.com