PlusMagi's Blog By Pitt Phunsanit Api Integration,Backend การทำ Request Timeout และการยกเลิก Request ใน Fetch API ด้วย AbortController

การทำ Request Timeout และการยกเลิก Request ใน Fetch API ด้วย AbortController

ในโลกของการพัฒนาเว็บแอปพลิเคชันสมัยใหม่ การสื่อสารกับ API ภายนอกเป็นหัวใจหลักของการทำงาน แต่สิ่งที่นักพัฒนาต้องเผชิญอยู่เสมอคือปัญหาความล่าช้าของเครือข่าย (Network Latency) หรือการตอบสนองที่ไม่มีกำหนดเวลานั้นเป็นสิ่งที่หลีกเลี่ยงไม่ได้ การปล่อยให้โค้ดรอคำตอบจากเซิร์ฟเวอร์ไปเรื่อย ๆ โดยไม่มีกลไกควบคุม ไม่เพียงแต่ส่งผลเสียต่อประสบการณ์ผู้ใช้งาน (UX) แต่ยังทำให้ทรัพยากรของเบราว์เซอร์ถูกผูกไว้โดยไม่จำเป็น ดังนั้น การจัดการวงจรชีวิตของการเรียกข้อมูล (Request Lifecycle) อย่างมีประสิทธิภาพจึงเป็นทักษะสำคัญที่ Senior Developer ทุกคนต้องเชี่ยวชาญ

🔌 AbortController: หัวใจของการยกเลิก Request อย่างสง่างาม

หัวใจสำคัญในการจัดการ Request Timeout และการยกเลิกใน Fetch API คือการใช้ Web Standard ที่ทรงพลังอย่าง AbortController ก่อนหน้านี้ การทำงานกับ Promise ของ Fetch มักจะรอจนกว่าคำขอจะสำเร็จหรือล้มเหลวด้วยเหตุผลที่ชัดเจน แต่หากเกิดความล่าช้าเกินขีดจำกัดที่เรายอมรับได้ เราจำเป็นต้องมีกลไกในการ “ยกเลิก” (Cancel) คำขอนั้นอย่างสง่างาม (Graceful Cancellation) เพื่อป้องกันการค้างของ UI และการรั่วไหลของทรัพยากร

AbortController ทำหน้าที่เป็นตัวควบคุมสัญญาณ (Signal) ที่สามารถส่งคำสั่งยกเลิกไปยัง Promise หรือ API Call อื่น ๆ ได้อย่างแม่นยำ เมื่อเราสร้าง AbortController ขึ้นมา เราจะได้ทั้ง controller และ signal ซึ่ง signal นี้เองที่เราต้องส่งเข้าไปในอาร์กิวเมนต์ของ Fetch API เพื่อให้เบราว์เซอร์ทราบว่าคำขอนี้สามารถถูกยกเลิกได้เมื่อถึงเวลาที่กำหนด

💻 การใช้งานจริง: การตั้งค่า Timeout ด้วย AbortController

การจำลอง Timeout ใน JavaScript ไม่สามารถทำได้ด้วยการตั้งค่า Timeout บน Fetch API โดยตรง แต่เราสามารถใช้ AbortController ร่วมกับ setTimeout เพื่อสร้างกลไกการยกเลิกที่จำลองการหมดเวลาได้

JavaScript

// 1. สร้าง AbortController และ Signal<br>const controller = new AbortController();<br>const signal = controller.signal;<br><br>// 2. ตั้งค่า Timeout (เช่น 3 วินาที)<br>const timeoutId = setTimeout(() => {<br>  // เมื่อครบเวลา ให้เรียก abort() เพื่อยกเลิกคำขอ<br>  controller.abort();<br>}, 3000);<br><br>async function fetchDataWithTimeout() {<br>  try {<br>    // ส่ง signal เข้าไปใน Fetch API<br>    const response = await fetch('https://api.example.com/data', {<br>      signal: signal<br>    });<br>    const data = await response.json();<br>    console.log('Success:', data);<br>  } catch (error) {<br>    // ตรวจสอบว่าเกิดจากการยกเลิกหรือไม่<br>    if (error.name === 'AbortError') {<br>      console.error('Request was aborted due to timeout.');<br>    } else {<br>      console.error('An unexpected error occurred:', error);<br>    }<br>  } finally {<br>    // ต้องเคลียร์ setTimeout เสมอ เพื่อป้องกัน Memory Leak<br>    clearTimeout(timeoutId);<br>  }<br>}<br><br>fetchDataWithTimeout();

✨ แนวทางปฏิบัติที่ดีที่สุด (Best Practices)

  1. Always Clear Timeout: สิ่งสำคัญที่สุดคือการใช้ clearTimeout(timeoutId) ในบล็อก finally เสมอ เพื่อให้แน่ใจว่าแม้ว่าการเรียกข้อมูลจะสำเร็จก่อนที่ Timeout จะทำงาน ก็จะไม่เกิด Memory Leak จาก setTimeout ที่ค้างอยู่
  2. Error Handling: เมื่อเกิดการยกเลิก (Cancellation) Fetch API จะโยนข้อผิดพลาดที่มีชื่อว่า AbortError ออกมา ดังนั้นการใช้ try...catch และตรวจสอบ error.name === 'AbortError' จึงเป็นสิ่งจำเป็นในการแยกแยะระหว่างข้อผิดพลาดที่เกิดจาก Timeout กับข้อผิดพลาดของเครือข่ายจริง
  3. Resource Management: การใช้กลไกนี้ช่วยให้แอปพลิเคชันของคุณมีเสถียรภาพสูงขึ้นอย่างมาก เพราะคุณสามารถควบคุมวงจรชีวิตของทรัพยากรเครือข่ายได้อย่างชัดเจน

✅ บทสรุป: การเขียนโค้ดที่แข็งแกร่งและตอบสนอง

การทำความเข้าใจและนำ AbortController มาใช้ในการจัดการ Request Timeout ไม่ใช่แค่การแก้ไขบั๊ก แต่เป็นการยกระดับคุณภาพของโค้ดให้เป็นระดับ Senior Architect เพราะมันแสดงให้เห็นถึงความเข้าใจในเรื่องการจัดการทรัพยากร (Resource Management) และประสบการณ์ผู้ใช้งาน (UX) ที่ยอดเยี่ยม

ด้วยการใช้กลไกนี้ นักพัฒนาสามารถสร้างเว็บแอปพลิเคชันที่ตอบสนองได้อย่างรวดเร็วและเชื่อถือได้ แม้ในสภาวะเครือข่ายที่ผันผวน ทำให้โค้ดของคุณไม่เพียงแค่ทำงานได้ แต่ยังทำงานได้อย่างสง่างามและมีประสิทธิภาพสูงสุด