Promise, Async, Await ของ JS ES6+ ฉบับสั้นๆ ไม่พูดเยอะ เจ็บคอ แถม RxJS

อ่านฉันหน่อย: บทความนี้ใช้ 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 วินาที ไปดูตัวอย่างกัน

promise

1. Promise #

const upperAfter = (text, ms) => (
new Promise(
resolve => setTimeout(() => resolve(text.toUpperCase()), ms)
)
);

const main = () => {
console.log("start upperAfter('test',2000)")
upperAfter('test',2000)
.then( data => {
console.log(data)
console.log("Finish upperAfter('test',2000)")
})
}

เมื่อเรารัน 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 ใหม่

const main = async () => {
console.log("start upperAfter('test',2000)")
const data = await upperAfter('test',2000)
console.log(data)
console.log("Finish upperAfter('test',2000)")
}

เป็นไงล่ะ ทำงานได้เหมือนเดิม แต่ชีวิตง่ายขึ้นมั้ย ทีนี้เราก็ทำตัวเหมือนเขียน 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 จริงๆ ละคับ

Parse.User.logIn('user', 'pass', {
success: function (user) {
query.find({
success: function (results) {
results[0].save({ key: value }, {
success: function (result) {
// the object was saved
}
});
}
});
}
});

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

Parse.User.logIn('user', 'pass').then(function (user) {
return query.find();
}).then(function (results) {
return results[0].save({ key: value });
}).then(function (result) {
// the object was saved
}).catch(function (err) {
// an error happened somewhere in the process
});

เป็นไงบ้าง ดูง่ายขึ้นเยอะมั้ย ครับ

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

อ่านเพิ่มเติม #


Cross published at Medium.com

Comment

GO BACK TO HOME