ป้ายกำกับ: Async/await

เขียน Fetch API ให้ Clean และอ่านง่ายขึ้นด้วย async/await แทนการซ้อน Promise/Callbackเขียน Fetch API ให้ Clean และอ่านง่ายขึ้นด้วย async/await แทนการซ้อน Promise/Callback

ในโลกของการพัฒนาเว็บสมัยใหม่ การจัดการข้อมูลแบบ Asynchronous (ไม่พร้อมกัน) เป็นสิ่งที่หลีกเลี่ยงไม่ได้ ไม่ว่าจะเป็นการเรียกข้อมูลจาก API ภายนอก การรอการตอบกลับจากเซิร์ฟเวอร์ หรือการทำงานที่ต้องรอให้คอมโพเนนต์ต่าง ๆ โหลดเสร็จสิ้น

หากเราจัดการกับงานเหล่านี้ด้วยรูปแบบ Promise Chaining หรือ Callback ที่ซ้อนกันลึกเกินไป โค้ดของเราจะเริ่มมีโครงสร้างที่อ่านยาก (Promise Hell) และการจัดการข้อผิดพลาดก็ยุ่งเหยิง ทำให้บำรุงรักษาและแก้ไขบั๊กได้ยากอย่างยิ่ง


✨ ปัญหา: Promise Chaining ที่ซับซ้อน

เมื่อเราต้องเรียก API หลายตัวตามลำดับ (Sequential API Calls) เช่น ต้องดึง User ID ก่อน แล้วจึงใช้ ID นั้นไปดึงข้อมูล Post และสุดท้ายใช้ Post ID ไปดึง Comment การใช้ Promise Chaining จะทำให้โค้ดดูยาวและซับซ้อนอย่างรวดเร็ว

JavaScript

// ❌ ตัวอย่างการใช้ Promise Chaining แบบเดิม (อ่านยาก) 
fetchUser(userId)
  .then(user => fetchPosts(user.id))
  .then(posts => fetchComments(posts[0].id))
  .then(comments => {
    console.log('Success:', comments);
  })
  .catch(error => {
    console.error('Error:', error);
  });

🚀 ทางออก: การใช้ async/await เพื่อความสะอาดและเป็นระเบียบ

หัวใจสำคัญของการปรับปรุงโค้ดคือการใช้ไวยากรณ์ (Syntax) ที่เรียกว่า async/await ซึ่งเป็นคุณสมบัติที่ถูกสร้างขึ้นมาเพื่อทำให้การเขียนโค้ด Asynchronous ดูเหมือนกับการทำงานแบบ Synchronous มากที่สุด โดยพื้นฐานแล้วมันไม่ได้เปลี่ยนวิธีการทำงานของ Promise แต่เป็นการให้เครื่องมือในการ “รอ” ผลลัพธ์อย่างมีระเบียบ ทำให้เราสามารถใช้โครงสร้าง try...catch ที่คุ้นเคยสำหรับการจัดการข้อผิดพลาดได้ทันที

การใช้ await หน้าคำสั่งที่คืนค่า Promise (เช่น fetch()) จะทำให้ JavaScript หยุดการทำงานชั่วคราว ณ จุดนั้น จนกว่า Promise นั้นจะถูก Resolve หรือ Reject ซึ่งทำให้ Flow การทำงานของโปรแกรมสามารถติดตามได้ง่ายเหมือนกับการอ่านขั้นตอนปกติ

JavaScript

// ✅ ตัวอย่างการใช้ async/await (อ่านง่ายและเป็นระเบียบ) 
async function fetchAllData(userId) {
  try {
    // 1. await จะรอจนกว่า fetchUser จะเสร็จสมบูรณ์
    const user = await fetchUser(userId);
    
    // 2. ใช้ผลลัพธ์ (user.id) ในการเรียก API ถัดไป
    const posts = await fetchPosts(user.id);
    
    // 3. ทำซ้ำจนจบขั้นตอน
    const comments = await fetchComments(posts[0].id);
    
    console.log('Success:', comments);
  } catch (error) {
    // การจัดการข้อผิดพลาดทำได้ง่ายด้วย try...catch
    console.error('An error occurred:', error);
  }
}

💡 ข้อดีที่เหนือกว่าของการใช้ async/await

  • ความสามารถในการอ่าน (Readability): โค้ดดูเป็นลำดับขั้นตอน (Sequential) เหมือนโค้ด Synchronous ทั่วไป ทำให้ผู้พัฒนาคนอื่นเข้าใจ Flow ได้ทันที
  • การจัดการข้อผิดพลาด (Error Handling): สามารถใช้ try...catch ได้อย่างเป็นธรรมชาติ ทำให้การดักจับข้อผิดพลาดทำได้ง่ายกว่าการใช้ `.catch()` ที่ปลายทางของ Promise Chain
  • ความกระชับ (Conciseness): ลดการใช้ `.then()` ซ้ำ ๆ ทำให้โค้ดสั้นลงและมีประสิทธิภาพมากขึ้น

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

การเปลี่ยนมาใช้ async/await ไม่ใช่แค่การเปลี่ยนไวยากรณ์ แต่เป็นการยกระดับมาตรฐานการเขียนโค้ด JavaScript ให้มีความเป็นมืออาชีพมากขึ้น สิ่งสำคัญที่ควรจำคือ:

  1. async: ต้องประกาศฟังก์ชันด้วยคีย์เวิร์ด async เสมอ เพื่อให้สามารถใช้ await ภายในฟังก์ชันนั้นได้
  2. await: ใช้ await หน้าการเรียก Promise ทุกครั้งที่ต้องการรอผลลัพธ์ก่อนดำเนินการขั้นตอนถัดไป
  3. การจัดการข้อผิดพลาด: ห่อหุ้มโค้ดทั้งหมดที่เกี่ยวข้องกับการเรียก API ด้วย try...catch เพื่อให้มั่นใจว่าโปรแกรมจะจัดการกับข้อผิดพลาดได้อย่างสง่างาม

การใช้ async/await อย่างถูกต้องจะช่วยให้โค้ดของคุณสะอาดตา (Clean Code) มีความน่าเชื่อถือ และง่ายต่อการบำรุงรักษาในระยะยาวได้อย่างแท้จริง