Promise, Async, Await ของ JS ES6+ ฉบับผอมเพรียว ไม่พูดเยอะ เจ็บคอ แถม RxJS

ขอบคุณรูปจาก Anika Huizinga on Unsplash
อ่านฉันหน่อย: บทความนี้ใช้ javascript ES6 นะครับ ใครยังไม่ชินไปตามอ่านได้ใน Cheat sheet นี้เลย มีภาษาไทยด้วย https://github.com/mbeaudru/modern-js-cheatsheet/blob/master/translations/th-TH.md
หมายเหตุ ต่อไป: ผมเขียน Python, C เป็นหลักนะครับ Java เป็นรอง แต่เขียน Async บน Java ด้วย ดังนั้น อาจจะไม่ถูกใจขา JS

สวัสดีครับ บล็อกนี้มาสั้นๆ ไม่เกริ่นทีมา ว่าทำไมถึงใช้ และหลักการต่างๆ ข้ามไว้ก่อน เพราะเราขี้เกียจเขียน (ไว้ค่อยกลับมาเขียน 555)

สรุปสั้นๆ

  • ใช้ Promise เพื่อแก้ปัญหา Callback Hell (มีแถม ท้ายบล็อก)
  • ใช้ Async, Await เพื่อไม่ต้องใช้ .then() แล้วยังไงล่ะ ไปดู
  • เนื่องจาก Promise resolve ได้แค่ครั้งเดียว ถ้าอยาก resolve หลายครั้ง เช่นข้อมูลแบบ stream ใช้ RxJS เพื่อแก้ปัญหา

สรุปจบ ไปดูโค๊ด

เราจะเขียน Promise กันง่ายๆ คือ ให้ฟังชั่นที่ทำงานนานๆ ตัวนึงชื่อ upperAfter โดยทำหน้าที่แปลงเป็นตัวพิมพ์ใหญ่ หลังจาก 2 วินาที ไปดูตัวอย่างกัน เป็นรูป

ผลลัพธ์การทำงาน
ลองทดสอบรันโค้ดได้เลย

1. Promise

เมื่อเรารัน main() แล้ว มันจะทำงานดังนี้

  1. เรียก upperAfter('test',2000) จะ return เป็น Promise ออกมา
  2. object ของ promise จะสามารถต่อด้วย .then() หรือ .catch() ก็ได้ 
    - ถ้าทำสำเร็จก็ใช้ .then() (คือค่า ที่ถูก resolve ออกมา ในที่นี้คือ text.toUpperCase())
    - ถ้าทำไม่สำเร็จก็ใช้ .catch() (คือค่า ที่ถูก reject ออกมา )
  3. เมื่อเรียก .then() ค่าของข้อความจะมาใส่มาใน data เราก็สามารถเอา data ไปต้มยำทำแกงอะไรก็ได้ เย้ จบ!

ข้อสังเกตุ คือเราใช้ .then() เพื่อทำให้ Blocking i/O หรือ Synchronous นั้นเอง คล้ายกับการเรียก callback นั้นแล แต่ .then() เราสามารถต่อกันได้ ทำให้โค้ดสวยมากขึ้น และ debug ง่ายขึ้นนะ

2. Async, Await

เอาโค้ดข้างบนมาแก้ main ใหม่

เป็นไงล่ะ ทำงานได้เหมือนเดิม แต่ชีวิตง่ายขึ้นมั้ย ทีนี้เราก็ทำตัวเหมือนเขียน Blocking I/O หรือ Synchronous แบบ C, Python ได้แล้ว เจ๋งป่ะล่ะ

ข้อสังเกตุ ฟังก์ชัน main() ต้องเป็น async เพื่อบอกว่าฟังก์ชันนี้มี การทำ blocking I/O หรือ Synchronous อยู่นะ เราใส่ await หน้า promise นั้นเอง มันจะ auto .then() ให้เลย สะดวกสุดๆ

ในบรรทัดนี้ const data = await upperAfter('test',2000) อารมณ์เหมือนเราได้ค่า data มาเลย แล้วก็เอาไปทำอะไรต่อก็ได้ ไม่ต้องอยู่ใน .then() แล้ว

ก่อนปิดบล็อก

อ่าวจบแล้ว? RxJS ล่ะ เอาแค่นี้ก่อน พอรู้ข้อจำกัดของการใช้ Promise แล้ว คราวหน้า เราสามารถไปใช้ RxJS ได้

ของแถม แล้ว Promise มาช่วยแก้ปัญหา Callback Hell ยังไง

อันนี้เอาตัวอย่างมาจาก โปรเจ็ค promise-it-wont-hurt ของ https://nodeschool.io/

อันนี้เค้าเรียกกันว่า Callback Hell ถ้ามีมากกว่าหลายชั้นก็นี้ก็ hell จริงๆ ละคับ

แล้วถ้าใช้ Promise ช่วยล่ะ

เป็นไงบ้าง ดูง่ายขึ้นเยอะมั้ย ครับ
พอล่ะไม่อธิบายเยอะ เจ็บขอ แล้วพบกันใหม่ครับ

กราบขอบพระคุณแหล่งที่มาต่างๆ

thanks https://carbon.now.sh for code highlighting