ทำความรู้จักกับ Deferreds

Deferreds เรียกได้ว่าเป็นเทคนิคที่ใช้จัดการกับการทำงานแบบ asynchronous ที่ใช้เวลานานๆ กว่าจะทำงานเสร็จค่อยส่งผลกลับมา เปลี่ยนเป็นส่ง deferred object กลับมาทันที จากนั้นก็ค่อยนำเอา deferred object ไปผูกฟังก์ชันที่ต้องการให้ทำต่อหรือเรียกว่า callback function ซิ่ง callback จะถูกเรียกใช้งานทันทีหลังจากที่ผลจาก asynchronous ส่งกลับมา

Promises เป็นรูปแบบ (model) หรืออธิบายง่ายๆ ก็คือชื่อของ ผลที่ได้จาก asynchronous (deferred results) ที่อธิบายไว้ได้บนครับ

มาดูตัวอย่างกันดีกว่า สมมติว่าเรากำลังสร้างเว็บไซต์ขึ้นมาเว็บหนึ่งที่มีการเรียกใช้ API ของเว็บอื่น ที่ทำไว้ให้เราเรียกใช้ แต่อาจจะด้วยสาเหตุที่เน็ตอาจจะช้าหรืออะไรก็ตาม ส่งผลให้ใช้เวลานานกว่าผลที่เราเรียกผ่าน API จะส่งกลับมา ซึ่งตรงนี้จะทำให้เว็บไซต์ของเราก็จะต้องรอ (blocking) จนกว่า API จะส่งค่ากลับมา ซึ่ง Deferred จะเข้ามาเป็นพระเอกเพื่อแก้ปัญหาตรงจุดนี้ครับ

Promise/A มีการกำหนดฟังก์ชันขึ้นมาชื่อ “then” ที่ใช้สำหรับลงทะเบียน (register) callbacks ให้กับ promise และรับผลลัพธ์ที่ส่งกลับมา ลองดู pseudo-code จะได้เข้าใจมากขึ้นครับ:

promise = callToAPI( arg1, arg2, ...);

promise.then(function( futureValue ) {
    /* จัดการกับข้อมูลที่ส่งกลับมา */
});

promise.then(function( futureValue ) {
    /* จัดการกับข้อมูลที่ส่งกลับมาอีกครั้ง */
});

promise มีสถานะที่เราต้องรู้จักอยู่ 2 สถานะด้วยกัน คือ

  1. resolved = ข้อมูลส่งกลับมาได้สมบูรณ์
  2. rejected = เกิดข้อผิดพลาดทำให้ไม่มีข้อมูลส่งกลับมา

แต่ก็ยังดีที่ฟังก์ชัน then รับ 2 parametors คือ สำหรับสถานะ resolved และ rejected ดังนั้น pseudo-code ข้างบนก็จะแก้ไขใหม่ได้เป็น ดังนี้ครับ

promise.then(function( futureValue ) {
    /* เมื่อได้รับข้อมูลกลับมา */
}, function() {
    /* เมื่อเกิดข้อผิดพลาดขึ้น */
});

แต่ในการใช้งานจริงๆ นั้นแอพพลิเคชั่นของเราจำเป็นจะต้องมีการเรียกใช้ข้อมูลจากหลายๆ API ที่จะส่งข้อมูลกลับมาหลายค่า (จากแต่ละ API ที่เรียก) ในกรณีนี้นี่เองที่จะต้องมีฟังก์ชัน when ขึ้นมา

when(
    promise1,
    promise2,
    ...
).then(function( futureValue1, futureValue2, ... ) {
    /* เมื่อ promises ทั้งหมดได้รับข้อมูลส่งกลับมาและอยู่ในสถานะ resolved */
});

ตัวอย่างการใช้ฟังก์ชัน when ก็อย่างเช่น เราสั่งให้ animations ที่ทำงานพร้อมกันอยู่ 2 animations หลังจากที่ทั้งสอง animations ทำงานเสร็จ แล้วให้มีข้อความเตือนขึ้นมา เป็นต้นครับ

var promise1 = $( "#id1" ).animate().promise();
var promise2 = $( "#id2" ).animate().promise();
when(
    promise1,
    promise2
).then(function() {
    alert('เรียบร้อยแล้ว');
});

อ่านข้อมูลเพิ่มเติมได้ที่: Deferreds | jQuery Learning Center