เมื่อวานไปงาน Meetup เกี่ยวกับ Promise มา ซึ่งจัดที่ GeekyBase
เมื่อฟังไปแล้วสิ่งที่อาจจะทำให้งงได้เล็กน้อย
ก็คือที่มาที่ไปของปัญหา Callback หรือที่เรียกว่า Callback hell
และก็สามารถแก้ไขหรือเยียวยาให้ดีขึ้น
ด้วย pattern หนึ่งที่เรียกว่า Promise

จากที่ blog เรื่อง ทำความเข้าใจกับ Callback และ Promise ใน Asynchronous programming  

มาครั้งนี้ลองมาดูตัวอย่างที่แสดงให้เห็นรูปแบบการใช้งาน callback กันหน่อย

ซึ่งจะเขียนด้วย JavaScript ซึ่งมีขึ้นตอนการทำงานดังนี้
1. ดึงข้อมูลตำแหน่งปัจจุบันผ่าน geolocation จะได้ตำแหน่ง latitude และ longitude
2. นำตำแหน่งที่ได้ไปค้นหาข้อมูลเพิ่มเติม เช่น ประเทศอะไร ผ่าน Google map api
3. แสดงผลลัพธ์

สามารถเขียนโปรแกรมโดยใช้ callback ดังนี้

คำอธิบาย
จะเห็นได้ว่า function getLocation() จะส่ง callback function ชื่อว่า lookupCountry
และใน function lookupCountry จะส่ง callback function ชื่อว่า displayResults

โดยสามารถเขียนภาพการทำงานได้ดังนี้

Screen Shot 2557-06-22 at 12.45.11 PM

จากการโปรแกรมในรูปแบบนี้ พบว่า code ที่ได้มานั้นจะผูกมัดกันอย่างมาก
เนื่องจากมีการเรียกใช้งานซ้อนกันไปเรื่อยๆ
ส่งผลให้การดูแลรักษาก็ยากขึ้นตามระเบียบ
(ในตัวอย่างนี้ยังไม่มีส่วน การดักจับความผิดพลาดต่างๆ)

ดังนั้นเราลองมาเขียนโปรแกรมนี้ใหม่ด้วย Promise ของ jQuery กันหน่อยดีกว่า

ซึ่งจะใช้งาน jQuery deferred object
โดยในแต่ละ function จะส่ง promise object ออกมา
ทำให้แต่ละ function แยกทำงานกันอย่างชัดเจน
แต่ละ function ไม่ต้องมาร้อยเรียงการทำงานกัน
เหมือนในตัวอย่างที่ 1 เลย

รูปแบบของ promise pattern นี้ได้รับแรงบันดาลใจมากจาก
KISS ( Keep it simple, stupid ) นั่นคือเราจะทำการแยกส่วนการทำงานออกจากกัน (Separation of Concern)
โดยสนใจที่ตัว business logic ให้มาก แล้วจึงนำแต่ละส่วนการทำงานเรียงร้อยเรียงกันทำงานต่อไป

การทำงานของ Promise object จะเป็นดังรูป

sm

โดย function getLocation() และ lookupCountry() จะทำงานแยกกันชัดเจน
และแต่ละ function จะส่ง promise object ออกมาเสมอ ดังต่อไปนี้

และสิ่งที่ขาดไปไม่ได้เลยก็คือ การเรียงร้อย flow การทำงานของ function ต่างๆ ที่เราต้องการ ดังนี้

คำอธิบาย
ในการร้อยเรียง flow การทำงานจะเริ่มตั้งแต่ การเริ่มทำงานที่ function getPosition()
เมื่อทำงานที่ function getPosition() เสร็จแล้ว จะเข้าทำงานที่ function lookupCountry() ต่อ
ถ้าทำงานสำเร็จทุกอย่างแล้ว จะเข้าทำงานที่ function displayResults() เพื่อแสดงข้อมูลตำแหน่งปัจจุบัน
แต่ถ้าการทำงานมีความผิดพลากเกิดขึ้น จะเข้าทำงานที่ function displayError() เพื่อแสดงรายละเอียดความผิดพลาด

รูปภาพแสดงการทำงานของ Promise object

Screen Shot 2557-06-22 at 1.32.05 PM

ในส่วนนี้มันจะสำคัญมากๆ ซึ่งเราต้องคิดและออกแบบก่อนการทำงานเสมอ

ตัวอย่างโปรแกรมแบบเต็มๆ เป็นดังนี้

จากตัวอย่างนี้ น่าจะพอทำให้เห็นว่า การใช้ callback ทำให้เกิดปัญหาอะไรบ้าง (แต่ไม่ใช่จะมีปัญหาเสมอ)
และที่มาที่ไปของการใช้งาน promise มาเพื่อแก้ไขปัญหาของ callback
หรือเข้าใจว่า promise ใช้งานอย่างไร มี pattern อย่างไร
มันจะทำให้เราสามารถเลือกได้ว่า จะใช้แนวทางใดในเหตุการณ์ต่างๆ ได้ดียิ่งขึ้น

เหนือสิ่งอื่นใด ต้องเลือกวิธีการให้เหมาะสมต่อการใช้งานนั้นๆ จะเป็นการดีที่สุด …