Event Loop: Call Stack, Queue และ Microtasks
มองเห็นภาพการทำงานของ JavaScript ตั้งแต่ call stack คิวงาน และ microtasks จาก Promise รวมถึงเหตุผลที่ส่วนติดต่อผู้ใช้ไม่หยุดตอบสนองระหว่างการทำงานแบบอะซิงโครนัส
Event Loop: Call Stack, Queue และ Microtasks เป็นบทเรียน Frontend Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Frontend Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน
JavaScript เป็นแบบเธรดเดียว
JavaScript ทำงานบนเธรดเดียว จึงประมวลผลโค้ดได้ครั้งละหนึ่งส่วนเท่านั้น ถึงอย่างนั้นก็ยังจัดการการดำเนินการแบบอะซิงโครนัสนับพันรายการ เช่น คำขอเครือข่าย ตัวจับเวลา และเหตุการณ์ส่วนติดต่อผู้ใช้ โดยไม่บล็อกการทำงานได้ แล้วทำได้อย่างไร คำตอบคือ วงจรเหตุการณ์
สแตกการเรียก
สแตกการเรียกเป็นพื้นที่ที่ JavaScript ใช้ติดตามว่าฟังก์ชันใดกำลังทำงานอยู่ เมื่อมีการเรียกฟังก์ชัน ระบบจะใส่เฟรมเข้าไป เมื่อฟังก์ชันส่งคืนค่า ระบบจะนำเฟรมนั้นออก หากสแตกเต็มจากการเรียกซ้ำไม่รู้จบ จะเกิดสแตกโอเวอร์โฟลว์
function c() { /* does something */ }
function b() { c(); }
function a() { b(); }
a();
// Call stack during c():
// c ← top
// b
// a
// (anonymous)API บนเว็บ — ส่งต่องานออกไป
เมื่อ JavaScript เรียกใช้ฟังก์ชันแบบอะซิงโครนัส (setTimeout, fetch, addEventListener) งานจะถูกส่งต่อให้กับ API บนเว็บ ในเบราว์เซอร์ เอนจิน JS จะทำงานต่อที่บรรทัดถัดไป โดยไม่ต้องรอ
console.log('1');
setTimeout(() => console.log('2'), 0); // handed to Web API
console.log('3');
// Output: 1, 3, 2คิวงาน (คิวแมโครทาสก์)
เมื่อการดำเนินการของ API บนเว็บเสร็จสิ้น (ตัวจับเวลาทำงาน หรือการดึงข้อมูลได้ผลลัพธ์) ฟังก์ชันเรียกกลับจะถูกนำไปใส่ใน คิวงาน (คิวแมโครทาสก์) ลูปเหตุการณ์จะย้ายฟังก์ชันเรียกกลับไปยังสแตกการเรียกใช้ก็ต่อเมื่อสแตกว่างเปล่า
คิวไมโครทาสก์
พรอมิสใช้ คิวไมโครทาสก์ ซึ่งเป็นคิวที่มีลำดับความสำคัญสูง หลังจากงานแต่ละงานเสร็จสิ้นและก่อนเริ่มงานถัดไป ไมโครทาสก์ที่ค้างอยู่ทั้งหมดจะถูกประมวลผล ไมโครทาสก์จะทำงานก่อนแมโครทาสก์ถัดไปเสมอ
console.log('1');
setTimeout(() => console.log('timeout'), 0); // macrotask
Promise.resolve().then(() => console.log('promise')); // microtask
console.log('2');
// Output: 1, 2, promise, timeoutลูปเหตุการณ์ทำงานอย่างไร
อัลกอริทึมของลูปเหตุการณ์: 1) ดำเนินงานปัจจุบันจากสแตกการเรียกใช้จนกว่าสแตกจะว่าง 2) ประมวลผลไมโครทาสก์ทั้งหมดในคิว 3) แสดงผลหน้าจอเมื่อเหมาะสม 4) เลือกแมโครทาสก์ถัดไปแล้วทำซ้ำ
queueMicrotask()
queueMicrotask(fn) จะจัดกำหนดการให้ฟังก์ชันเรียกกลับทำงานในคิวไมโครทาสก์โดยไม่สร้างพรอมิส โดยทั่วไปไม่จำเป็นต้องเรียกใช้โดยตรง แต่มีประโยชน์ต่อการทำความเข้าใจว่าคลังโปรแกรมต่าง ๆ จัดกำหนดการทำงานอย่างไร
queueMicrotask(() => console.log('microtask'));
console.log('sync');
// Output: sync, microtaskเหตุใดงานที่ใช้เวลานานจึงทำให้ส่วนติดต่อผู้ใช้ค้าง
หากงานแบบซิงโครนัสทำงานนานเกินไป (เช่น ลูปที่ประมวลผลข้อมูลจำนวนมากอย่างต่อเนื่อง) ลูปเหตุการณ์จะไม่สามารถประมวลผลเหตุการณ์ของส่วนติดต่อผู้ใช้หรือแสดงผลหน้าจอได้ หน้าจะค้าง ให้แบ่งงานที่ใช้เวลานานเป็นส่วนย่อย ๆ ด้วย setTimeout เพื่อคืนการควบคุมให้ลูปเหตุการณ์
// Bad — blocks the UI for seconds:
for (let i = 0; i < 10_000_000; i++) { /* heavy work */ }
// Better — yield periodically:
async function processInChunks(items) {
for (let i = 0; i < items.length; i++) {
process(items[i]);
if (i % 100 === 0) await new Promise(r => setTimeout(r, 0)); // yield
}
}เวิร์กเกอร์บนเว็บ — การทำงานแบบขนานอย่างแท้จริง
สำหรับงานที่ใช้ CPU อย่างหนัก ให้ใช้ เวิร์กเกอร์บนเว็บ ซึ่งเป็นเธรดแยกที่มีลูปเหตุการณ์ของตนเอง เวิร์กเกอร์ติดต่อสื่อสารกับเธรดหลักผ่าน postMessage โดยไม่มีหน่วยความจำที่ใช้ร่วมกันและไม่มีเงื่อนไขการแข่งขัน
requestAnimationFrame
requestAnimationFrame(callback) จะจัดกำหนดการให้ฟังก์ชันเรียกกลับทำงานก่อนที่เบราว์เซอร์จะวาดหน้าจอใหม่ ใช้สำหรับภาพเคลื่อนไหวที่ควบคุมด้วย JavaScript เพราะจะทำงานสอดคล้องกับอัตราการรีเฟรชของจอแสดงผล ซึ่งโดยทั่วไปอยู่ที่ 60 เฟรมต่อวินาที
function animate(timestamp) {
// update positions based on timestamp
element.style.transform = `translateX(${timestamp * 0.1 % 400}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);การเห็นภาพลูปเหตุการณ์
ตัวอย่างแบบโต้ตอบที่ latentflip.com/loupe ช่วยให้คุณวางโค้ดแล้วดูสแตกการเรียกใช้ API บนเว็บ คิวงาน และลูปเหตุการณ์ทำงานแบบช้าลงได้ เครื่องมือนี้จำเป็นอย่างยิ่งต่อการสร้างความเข้าใจเชิงสัญชาตญาณ
ตรวจสอบความเข้าใจ
หลังจากพรอมิสให้ผลสำเร็จ ฟังก์ชันเรียกกลับของ .then() จะทำงานในคิวใด
ทบทวน: ลูปเหตุการณ์
JavaScript ทำงานด้วยเธรดเดียว งานแบบอะซิงก์จะถูกส่งไปยัง API บนเว็บ ฟังก์ชันเรียกกลับจะกลับมาผ่านคิวงาน (setTimeout และฟังก์ชันเรียกกลับของการดึงข้อมูล) หรือคิวไมโครทาสก์ (พรอมิส) ลูปเหตุการณ์จะประมวลผลไมโครทาสก์ทั้งหมดหลังงานแต่ละงานเสร็จ ก่อนการแสดงผลครั้งถัดไปหรือแมโครทาสก์ถัดไป โค้ดซิงโครนัสที่ทำงานนานจะขัดขวางทุกอย่าง
คำถามที่พบบ่อย
บทเรียน “Event Loop: Call Stack, Queue และ Microtasks” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Event Loop: Call Stack, Queue และ Microtasks” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Frontend Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Event Loop: Call Stack, Queue และ Microtasks”
มองเห็นภาพการทำงานของ JavaScript ตั้งแต่ call stack คิวงาน และ microtasks จาก Promise รวมถึงเหตุผลที่ส่วนติดต่อผู้ใช้ไม่หยุดตอบสนองระหว่างการทำงานแบบอะซิงโครนัส คุณปฏิบัติ Frontend Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Frontend Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Frontend Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “Event Loop: Call Stack, Queue และ Microtasks” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Frontend Academy นี้ได้ไหม
ได้ บทเรียน Frontend Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Event Loop: Call Stack, Queue และ Microtasks
- Callback และ Callback Hell
- Promise: then, catch, finally และ Promise.all
- async/await และการจัดการข้อผิดพลาด