อ่านฉันหน่อย: บทความนี้ใช้ javascript ES6 นะครับ ใครยังไม่ชินไปตามอ่านได้ใน Cheat sheet นี้เลย มีภาษาไทยด้วย
https://github.com/mbeaudru/modern-js-cheatsheet/blob/master/translations/th-TH.md
หมายเหตุ ต่อไป: ผมเขียน Python, C เป็นหลักนะครับ Java เป็นรอง แต่เขียน Async บน Java ด้วย ดังนั้น อาจจะไม่ถูกใจขา JS
สวัสดีครับ บล็อกนี้มาสั้นๆ ไม่เกริ่นทีมา ว่าทำไมถึงใช้ และหลักการต่างๆ ข้ามไว้ก่อน เพราะเราขี้เกียจเขียน (ไว้ค่อยกลับมาเขียน 555)
สรุปสั้นๆ
.then() แล้วยังไงล่ะ ไปดูresolve ได้แค่ครั้งเดียว ถ้าอยาก resolve หลายครั้ง เช่นข้อมูลแบบ stream ใช้ RxJS เพื่อแก้ปัญหาสรุปจบ ไปดูโค๊ด
เราจะเขียน Promise กันง่ายๆ คือ ให้ฟังชั่นที่ทำงานนานๆ ตัวนึงชื่อ upperAfter โดยทำหน้าที่แปลงเป็นตัวพิมพ์ใหญ่ หลังจาก 2 วินาที ไปดูตัวอย่างกัน

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() แล้ว มันจะทำงานดังนี้
upperAfter('test',2000) จะ return เป็น Promise ออกมา.then() หรือ .catch() ก็ได้
.then() (คือค่า ที่ถูก resolve ออกมา ในที่นี้คือ text.toUpperCase()).catch() (คือค่า ที่ถูก reject ออกมา ).then() ค่าของข้อความจะมาใส่มาใน data เราก็สามารถเอา data ไปต้มยำทำแกงอะไรก็ได้ เย้ จบ!ข้อสังเกตุ คือเราใช้ .then() เพื่อทำให้ Blocking i/O หรือ Synchronous นั้นเอง คล้ายกับการเรียก callback นั้นแล แต่ .then() เราสามารถต่อกันได้ ทำให้โค้ดสวยมากขึ้น และ debug ง่ายขึ้นนะ
เอาโค้ดข้างบนมาแก้ 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-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