Promises ถูกนำเข้ามาใน ES6 อนุญาตให้เขียน asynchronous code ได้ง่ายโดยไม่ต้องจัดการกับ callback functions หลายระดับ ด้วย Promises ไม่ต้องกังวล multi-level callback functions ที่ยากต่อการเขียนและบำรุงรักษา
มีฟีเจอร์อีกอย่างใน JavaScript ทำให้เขียน asynchronous code ด้วย Promises ง่ายขึ้น: async/await functions ฟังก์ชันเหล่านี้ช่วยเขียนโค้ดที่ดู synchronous แต่จริงๆ ทำ asynchronous routines
ในคู่มือนี้ เราจะพูดถึง async/await function คืออะไร และวิธีใช้ในโค้ด มาเริ่มกัน!
Promises: ทบทวนความรู้
ก่อนพูดถึง async/await ต้องทบทวน Promises Promise แทน asynchronous operation บอกโค้ดว่า operation จะถูกดำเนินการ และถ้าสำเร็จ จะคืนค่า ไม่เช่นนั้น จะคืน error ให้โปรแกรม
Promise แทนค่าที่ยังไม่รู้ตอนสร้าง Promise คือคำมั่นสว่างว่า future values จะส่งกลับมา เนื่องจาก Promise เป็น object จึงต้อง capitalize
พิจารณาสถานการณ์นี้ คุณต้องดึง resource จาก API ใช้เวลา 1-2 วินาที แทนที่จะให้ user รอ คุณย้ายโค้ดเข้า Promise เพื่อให้โปรแกรมอื่นทำงานต่อได้
หมายความว่าคุณ render UI ของเว็บไซต์ต่อได้ขณะดึงข้อมูล ทันทีที่มีค่าคืนมา Promise จะส่งให้ main program
ตัวอย่าง Promise:
let sendCookies = new Promise(resolve => { setTimeout(() => { resolve("Your cookies have been sent!"); }, 1000); }); sendCookies.then(data => { console.log(data); })
โค้ดคืนค่า: Your cookies have been sent! เมื่อ execute sendCookies.then() Promise เริ่มทำงาน โปรแกรมรอ 1,000 milliseconds แล้วส่งค่า "Your cookies have been sent!" กลับไป main program
วิธีใช้ Async และ Await
ใน async/await function await statement บล็อกโค้ดไม่ให้ execute ภายใน async function จนกว่า Promise จะคืนค่า นั่นคือเหตุผลที่ developer บอกว่า async/await functions ดู synchronous แต่ทำ asynchronous tasks
พิจารณาตัวอย่างนี้:
function sendCookies() { return new Promise(resolve => { setTimeout(() => { resolve("Your cookies have been sent!"); }, 1000); }); } async function main() { const sendMessage = await sendCookies(); console.log(sendMessage); } main();
โค้ดคืนค่า: Your cookies have been sent! ใช้เวลา 1,000 milliseconds สำหรับ sendCookies() คืนค่า "Your cookies have been sent" ในกรณีนี้ เราประกาศ async function ให้โค้ดรอ promise resolve หรือ reject
Keyword "async" บอกโค้ดว่าเราต้องการ asynchronous operation ในฟังก์ชัน Keyword "await" บอกโค้ดให้รอคืนค่าของ sendCookies() Promise ก่อนดำเนินการต่อ
Async functions เสมอคืนค่า Promise
ใช้ Async และ Await กับหลายขั้นตอน
Async/await functions ใช้บ่อยที่สุดตอนมี multiple Promises ต้องจัดการ เรียกว่า Promises chaining เพราะโค้ดรอ Promise คืนค่าจากแต่ละขั้นตอนก่อนไปขั้นต่อไป:
function processOrder() { return new Promise(resolve => { setTimeout(() => { resolve("Your cookie order is being processed..."); }, 1000); }); } function sendCookies() { return new Promise(resolve => { setTimeout(() => { resolve("Your cookies have been sent!"); }, 1000); }); } async function main() { const processingMessage = await processOrder(); console.log(sendMessage); const sendMessage = await sendCookies(); console.log(sendMessage); }
โค้ดคืนค่า:
Your cookie order is being processed… Your cookies have been sent!
แต่ละขั้นตอนใช้เวลา 1,000 milliseconds sendCookies() ไม่ execute จนกว่า Promise จาก processOrder() จะคืนค่า
Async Expressions
มีสามวิธีใช้ async/await function
วิธีแรก คือ approach ที่แสดงในตัวอย่างก่อนหน้า: ผ่านการประกาศ functions ในตัวอย่างเราประกาศฟังก์ชันคืนค่า Promise แล้วใช้ "async" และ "await" เรียกใช้
คุณยังสามารถประกาศ async function ด้วย arrow functions:
const main = async () => { const sendMessage = await sendCookies(); console.log(sendMessage); }
โค้ดคืนค่า: Your cookies have been sent! เหมือนตัวอย่างแรก แต่ใช้ arrow function แทน main() function
เช่นกัน ใช้ function expression syntax:
const main = async function() { const sendMessage = await sendCookies(); console.log(sendMessage); }
โค้ดคืนค่า: Your cookies have been sent! เห็นได้ว่าผลลัพธ์เหมือนกัน แตกต่างแค่การประกาศฟังก์ชัน
Syntax นี้คล้ายตัวอย่างก่อนหน้ามาก ใช้ "function()" keyword แทน arrow function
ไม่มี best way สำหรับการประกาศ async/await ขึ้นอยู่กับโปรแกรมและ syntax ที่คุณชอบ แม้ arrow functions จะ concise ที่สุด แต่วิธีอื่นอาจดีกว่าในบางกรณี
ประมวลผล Web Requests ด้วย Async/Await
การใช้งาน async/await ที่พบบ่อยที่สุดคือประมวลผล web requests ด้วย API ที่ Promise-based เช่น fetch() อ่านเพิ่มเติมได้จาก beginner's guide to JavaScript fetch
พิจารณาตัวอย่างนี้:
async function retrieveComments() { const res = await fetch('https://jsonplaceholder.typicode.com/comments'); var comments = await res.json(); comments = comments.map(comment => comment.name); console.log(comments); } retrieveComments();
โค้ดคืนค่า:
["id labore ex et quam laborum", "quo vero reiciendis velit similique earum" …]
ตอน execute retrieveComments() เราใช้ "await" รอ fetch() statement รัน หมายความว่าโปรแกรมอื่นไม่ดำเนินการต่อจนกว่า web request จะเสร็จ เพราะ fetch() คืนค่า Promise
ตอน Promise คืนค่าจาก fetch() เราแปลงค่าที่ได้เป็น JSON แล้ว map ผ่าน object ดึงลิสต์ชื่อ comments ทั้งหมด พิมพ์ไปที่ console
วิธีจัดการ Error
ผมหวังว่า errors ไม่เกิดในโค้ด แต่เกิดจริง และเรา developers ต้องวางแผนไว้ ใน asynchronous function error handling ทำ synchronously ด้วย try…catch statement พิจารณาโค้ดนี้:
async function retrieveCookies() { const res = await fetch('https://thisapidoesnotexist.app/cookies'); var cookieNames = await res.json(); cookieNames = cookieNames.map(cookie => cookie.name); resolve(cookieNames); } async function printCookies() { const cookies = await retrieveCookies(); console.log(cookies); } printCookies().catch(res => console.log(res.message));
โค้ดคืนค่า:
NetworkError when attempting to fetch resource. โค้ดของเราทำงานได้ แต API ที่พยายามเข้าถึงไม่มีอยู่จริง หมายความว่า Promise ไม่สามารถคืนค่าข้อมูลได้ จึงคืน rejected Promise แทน
ในตัวอย่าง เราใช้ .catch() statement พิมพ์ error ที่ฟังก์ชันคืนถ้ามี ในกรณีนี้ เราใช้ reject('Error') บอกโค้ดว่า error เกิดขึ้น
ถ้า statement นี้ execute .catch() จะทำงานและพิมพ์ error นั้น
Async functions จับ syntax errors ได้เช่นกัน:
async function retrieveCookies() { const res = await fetch('https://thisapidoesnotexist.app/cookies'); var cookieNames = await res.json(); cookieNames = cookieNames.map(cookie => cookie.name); resolve(cookieNames); } async function printCookies() { try { const cookies = await retrieveCookies(); console.log(cookies); } catch(error) { console.log(error); } } printCookies();
โค้ดคืนค่า: NetworkError when attempting to fetch resource. ในตัวอย่าง เราใช้ try/catch เช็คว่า await method คืนค่า Promise สำเร็จหรือไม่ อีกครั้ง API ไม่ valid ทำให้โปรแกรม reject Promise ตอนนี้ "catch" ใน try/catch block execute ซึ่ง log error ไปที่ console
สรุป
Async/await functions ช่วยเขียน asynchronous operations ในโค้ด ตอนประกาศ async function คุณใช้ "await" keyword รอ operations resolve await keyword ต้องใช้กับฟังก์ชันที่คืนค่า Promise
ตอนนี้คุณพร้อมใช้ async/await JavaScript functions แบบมืออาชีพแล้ว!