Future/Promise คือรูปแบบการเขียนโปรแกรมแบบอะซิงโครนัสที่แสดงคอนเทนเนอร์สำหรับผลลัพธ์ของการดำเนินการที่ยังไม่เสร็จสมบูรณ์ ตาม Dart Documentation, 2025 Future คือผลลัพธ์แบบอ่านอย่างเดียวของการคำนวณที่เลื่อนออกไป Promise คือสัญญาแบบเขียนอย่างเดียวที่เติมผลลัพธ์นี้ Future ถูกใช้ใน Dart, Java, Scala และ C++ สำหรับเชน then/catch
ประเด็นสำคัญ
Future/Promise คือคู่ของอ็อบเจกต์ที่เชื่อมโยงกันซึ่งแบ่งผลลัพธ์อะซิงโครนัสออกเป็นสองบทบาท Promise สามารถเขียนผลลัพธ์ (resolve) หรือข้อผิดพลาด (reject) Future สามารถอ่านได้อย่างเดียว — ผ่าน callback (then, catchError) หรือผ่าน await การแยกนี้รับประกันว่าผู้บริโภคไม่สามารถเปลี่ยนแปลงผลลัพธ์ได้ มีเพียงใช้งานเท่านั้น
ภาษา Dart ใช้ Future เป็นกลไกอะซิงโครนัสหลัก Future<T> คือสัญญาที่จะรับค่าชนิด T ในอนาคต Future สามารถอยู่ในหนึ่งในสามสถานะ: unresolved (การดำเนินการกำลังดำเนินการ), resolved with value (เสร็จสมบูรณ์สำเร็จ) หรือ resolved with error (เสร็จสมบูรณ์ด้วยข้อผิดพลาด) เมื่อเปลี่ยนเป็นสถานะ resolved แล้ว Future จะไม่เปลี่ยนแปลงอีก
Promise ใน JavaScript คล้ายกับ Future ของ Dart แต่มี API ที่สมบูรณ์กว่า Promise รับ executor — ฟังก์ชันที่มีพารามิเตอร์ resolve และ reject เมธอดแบบสแตติก Promise.all, Promise.race, Promise.allSettled อนุญาตให้รวม promises หลายตัว แอปพลิเคชันสมัยใหม่ใช้ไวยากรณ์ async/await บน Promise
Future ทำงานบนพื้นฐานของ event loop — วงจรเหตุการณ์ที่ประมวลผลการดำเนินการอะซิงโครนัสโดยไม่บล็อกเธรดหลัก เมื่อฟังก์ชันอะซิงโครนัสถูกเรียก (เช่น http.get) ฟังก์ชันจะคืนค่า Future ทันที คำขอจริงทำงานในเบื้องหลัง ในขณะที่ event loop ยังคงประมวลผลเหตุการณ์อื่นๆ ต่อไป หลังจากการดำเนินการเสร็จสมบูรณ์ Future จะเปลี่ยนเป็นสถานะ resolved และ then จะถูกเรียก
Event loop คือกลไกสำคัญที่ Dart และ JavaScript สร้างขึ้น Event loop รักษาคิวสองคิว: คิว microtask (งานสั้น ดำเนินการก่อนเหตุการณ์ถัดไป) และคิวเหตุการณ์ (เหตุการณ์ IO, ตัวจับเวลา) Future.then วาง callback ในคิว microtask, Future.microtask — ดำเนินการสำคัญก่อนเฟรมถัดไป
เชนของ then() อนุญาตให้ประมวลผลผลลัพธ์ของการดำเนินการอะซิงโครนัสตามลำดับโดยไม่มี callback hell แต่ละ then() รับผลลัพธ์ของขั้นตอนก่อนหน้าและคืนค่า Future ใหม่ catchError() ที่จุดสิ้นสุดของเชนจัดการข้อผิดพลาดใดๆ ที่เกิดขึ้นในขั้นตอนใดๆ ทำให้โค้ดอะซิงโครนัสเป็นเชิงเส้นและอ่านง่าย
ใน Java CompletableFuture ขยายแนวคิด Future/Promise เมธอด supplyAsync() เริ่มงานอะซิงโครนัสใน ForkJoinPool.commonPool() thenApply() แปลงผลลัพธ์ thenCompose() เปิด CompletableFuture ที่ซ้อนกัน exceptionally() จัดการข้อผิดพลาดโดยคืนค่าเริ่มต้น allOf() และ anyOf() ทำงานเหมือน Promise.all และ Promise.race ใน JavaScript CompletableFuture รองรับการเสร็จสมบูรณ์ด้วยตนเองผ่าน complete() และ completeExceptionally() — ซึ่งคล้ายกับ Promise resolve/reject
Promise คือสัญญาที่มีหนึ่งในสามสถานะ: pending (รอดำเนินการ), fulfilled (สำเร็จ) หรือ rejected (ถูกปฏิเสธ) เมื่อเปลี่ยนเป็น fulfilled หรือ rejected แล้ว Promise จะไม่เปลี่ยนแปลงอีก — ซึ่งรับประกันความไม่แปรเปลี่ยนของผลลัพธ์สำหรับผู้บริโภคทั้งหมด เมธอด .then() จะถูกเรียกแบบอะซิงโครนัสหลังจากเปลี่ยนเป็นสถานะที่เสร็จสมบูรณ์ใดๆ
Promise.all รอให้ promises ทั้งหมดที่ส่งเข้ามาเสร็จสมบูรณ์และคืนค่าอาเรย์ของผลลัพธ์ในลำดับเดียวกัน หาก promise หนึ่งล้มเหลวด้วยข้อผิดพลาด — Promise.all ทั้งหมดจะเปลี่ยนเป็น rejected Promise.race คืนค่าผลลัพธ์ของ promise ที่เสร็จสมบูรณ์ตัวแรก (สำเร็จหรือข้อผิดพลาด) Promise.allSettled รอ promises ทั้งหมดโดยไม่คำนึงถึงข้อผิดพลาด — คืนค่าสถานะของแต่ละตัว
การเชน คือข้อได้เปรียบสำคัญของ Promise เหนือ callback แต่ละ .then() คืนค่า Promise ใหม่ ทำให้สามารถสร้างเชนที่มีความยาวตามต้องการ ข้อผิดพลาดในจุดใดๆ ของเชนจะถูกส่งต่อไปยัง .catch() ที่ใกล้ที่สุด เมธอด finally() ดำเนินการโค้ดหลังจากเชนเสร็จสมบูรณ์โดยไม่คำนึงถึงผลลัพธ์ — สำหรับการทำความสะอาดทรัพยากร
ตัวอย่างแรก — การสร้าง Future ผ่านฟังก์ชัน async และจัดการด้วย then/catchError:
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 1))
return "โหลดข้อมูลแล้ว"
}
fetchData()
.then((result) => print(result))
.catchError((error) => print("ข้อผิดพลาด: $error"))
ตัวอย่างที่สอง — การรวม Futures หลายตัวด้วย Future.wait:
Future<List<String>> loadAll() async {
final futures = [
fetchFromApi("/users"),
fetchFromApi("/posts"),
fetchFromApi("/comments")
]
final results = await Future.wait(futures)
return results
}
ตัวอย่างที่สาม — Promise ใน JavaScript ด้วยการสร้างด้วยตนเองและเชน then:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("เสร็จแล้ว")
}, 1000)
})
promise
.then(value => console.log(value))
.catch(err => console.error(err))
Future/Promise แตกต่างจากสไตล์ callback ตรงที่คืนค่าอ็อบเจกต์สัญญาแทนที่จะรับฟังก์ชัน callback เป็นอาร์กิวเมนต์ สไตล์ callback นำไปสู่การซ้อนกัน (callback hell) ในขณะที่ Future อนุญาตให้สร้างเชน then() แบบราบ ไวยากรณ์ async/awat ทำให้โค้ด Future เป็นเชิงเส้นมากขึ้น คล้ายกับโค้ดซิงโครนัส
Future แทนผลลัพธ์อะซิงโครนัสหนึ่งตัวพอดี — การปล่อยหนึ่งครั้ง หลังจากนั้น Future จะเสร็จสมบูรณ์ แตกต่างจาก Observable (Rx, ReactiveX) หรือ Flow (Kotlin Coroutines) ตรงที่ Future ไม่รองรับค่าหลายค่าเมื่อเวลาผ่านไป หากคุณต้องการสตรีมเหตุการณ์ — ใช้ Stream ใน Dart, Observable ใน Rx หรือ Flow ใน Kotlin
CompletableFuture ใน Java เป็นอะนาล็อกของ Promise ที่มี API ขยาย: supplyAsync, thenApply, thenCompose, exceptionally CompletableFuture อนุญาตให้รวมการดำเนินการอะซิงโครนัสหลายตัวผ่าน allOf, anyOf และยังอนุญาตให้ระบุ Executor ที่กำหนดเองสำหรับการดำเนินการ Scala Future ใช้ ExecutionContext เพื่อจัดการพูลเธรดและรองรับการประกอบผ่าน for-comprehension
ใน Dart รูปแบบ Future แตกต่างจาก Promise ใน JavaScript ตรงที่ Dart มีการกำหนดชนิดที่เข้มงวด: Future<String> รับประกันชนิดของค่าที่ส่งคืน ฟังก์ชัน async ใน Dart ต้องคืนค่า Future และคอมไพเลอร์จะตรวจสอบว่าเส้นทางทั้งหมดคืนค่าชนิดที่ถูกต้อง Future.wait เทียบเท่ากับ Promise.all — รับ Iterable<Future<T>> และคืนค่า Future<List<T>> Future.delayed และ Future.error เป็นโรงงานที่สะดวกสำหรับการทดสอบสถานการณ์อะซิงโครนัส
Future/Promise ถูกนำไปใช้ใน Python ผ่าน concurrent.futures.Future และ asyncio.Future concurrent.futures.ThreadPoolExecutor.submit() คืนค่า Future ซึ่งสามารถเรียก result() ได้ — การเรียกแบบบล็อก asyncio.Future เป็นคอนเทนเนอร์ที่เข้ากันได้กับ await สำหรับผลลัพธ์อะซิงโครนัสใน Asyncio asyncio.gather() ทำงาน coroutines หลายตัวพร้อมกันและคืนค่ารายการผลลัพธ์ คล้ายกับ Promise.all ใน JavaScript Python ยังใช้ asyncio.ensure_future ที่ใช้ callback และเชน add_done_callback สำหรับประกอบการดำเนินการอะซิงโครนัส แต่ในโค้ดสมัยใหม่ ไวยากรณ์ async/await กับ asyncio.Task เป็นที่นิยมกว่า
ในการพัฒนามือถือ Future ถูกใช้อย่างแข็งขันในแอปพลิเคชัน Flutter ทุกคำขอเครือข่ายจากแพ็กเกจ http หรือ dio คืนค่า Future FutureBuilder คือวิดเจ็ตที่รับ Future และสถานะ snapshot: connectionDone, hasData, hasError เมื่อได้รับข้อมูล snapshot.data จะมีผลลัพธ์ของ Future StreamBuilder เป็นอะนาล็อกสำหรับค่าหลายตัว FutureBuilder ขจัดการจัดการสถานะการโหลดด้วยตนเองผ่าน setState
Scala Future ใช้ ExecutionContext โดยปริยาย — พูลเธรดที่งานอะซิงโครนัสดำเนินการ การประกอบผ่าน map, flatMap, filter ทำงานเนื่องจาก Future เป็นโมแนด for-comprehension อนุญาตให้รวม Futures หลายตัวตามลำดับโดยไม่ซ้อนกัน: for { a <- futureA; b <- futureB } yield a + b Future.sequence ทำงานเหมือน Promise.all การตกกลับข้อผิดพลาดถูกนำไปใช้ผ่าน recover และ recoverWith
Future/Promise ใน C++ แสดงโดยคลาส std::future และ std::promise จากไลบรารี <future> std::async เริ่มฟังก์ชันอะซิงโครนัสและคืนค่า std::future std::promise อนุญาตให้ตั้งค่าด้วยตนเองผ่าน set_value() หรือข้อผิดพลาดผ่าน set_exception() แตกต่างจาก Dart และ JavaScript std::future.get() บล็อกเธรดจนกว่าจะได้รับผลลัพธ์ — นี่คือความแตกต่างสำคัญที่ต้องพิจารณาเมื่อออกแบบแอปพลิเคชัน C++ แบบหลายเธรด
เมื่อออกแบบ API ที่คืนค่า Future ให้ปฏิบัติตามกฎ แหล่งความจริงเดียว: คำขออะซิงโครนัสแต่ละครั้งถูกสร้างขึ้นครั้งเดียวและแคชผ่าน Future.memoize หากสองคอมโพเนนต์ขอข้อมูลเดียวกัน พวกเขาจะได้รับ Future เดียวกัน — ซึ่งป้องกันคำขอซ้ำ สำหรับ timeout ให้ใช้ Future.timeout (Dart) หรือ Promise.race พร้อมกับ timeout เพื่อรับประกันว่าการดำเนินการอะซิงโครนัสจะเสร็จสมบูรณ์ภายในช่วงเวลาที่กำหนด
รูปแบบลองใหม่ ใน Future ถูกนำไปใช้ผ่านเชนแบบเรียกซ้ำ: เมื่อข้อผิดพลาดใน catch ฟังก์ชันอะซิงโครนัสเดียวกันจะถูกเรียกด้วยความล่าช้า Exponential backoff เพิ่มช่วงเวลาระหว่างความพยายาม: 1 วินาที — 2 วินาที — 4 วินาที — สูงสุด 30 วินาที ใน Dart สิ่งนี้ถูกห่อหุ้มในส่วนขยายบน Future: future.retry(maxRetries: 3, delay: Duration(seconds: 1)) ใน Scala Future.zip รวมผลลัพธ์อิสระสองตัวเป็นทูเพิล — ทางเลือกสำหรับ Promise.all สำหรับสอง Future การยกเลิกไม่ได้รับการสนับสนุนใน Future มาตรฐาน แต่ถูกนำไปใช้ผ่าน CancellationToken หรือ AbortController ใน JavaScript
คำถามที่พบบ่อย
Future คือคอนเทนเนอร์แบบอ่านอย่างเดียวสำหรับอ่านผลลัพธ์อะซิงโครนัสผ่าน then หรือ await Promise คือสัญญาแบบเขียนอย่างเดียวที่รับค่าผ่าน resolve() และเชื่อมโยงกับ Future ใน Dart และ JavaScript แนวคิดเหล่านี้รวมกัน: Future/Promise เป็นคลาสเดียวกัน ใน Java และ Scala แยกกัน
Future แทนผลลัพธ์อะซิงโครนัสเดียว — มันปล่อยค่าหนึ่งค่าและเสร็จสมบูรณ์ Observable (Rx) ปล่อยหลายค่าเมื่อเวลาผ่านไป — มันคือสตรีมอะซิงโครนัส หากคุณต้องการการตอบสนอง HTTP หนึ่งครั้ง — ใช้ Future หากคุณต้องการสตรีมการเปลี่ยนแปลงฐานข้อมูล — ใช้ Observable หรือ Stream
async/await คือน้ำตาลทางไวยากรณ์เหนือ Future/Promise คีย์เวิร์ด async ทำเครื่องหมายฟังก์ชันเป็นอะซิงโครนัส — มันคืนค่า Future await หยุดการทำงานชั่วคราวจนกว่า Future จะเสร็จสมบูรณ์ โดยไม่บล็อกเธรด ใน Dart, JavaScript, Python และ C# async/await ได้แทนที่เชน then ในสถานการณ์ส่วนใหญ่
ใน Dart ใช้ .catchError() ที่จุดสิ้นสุดของเชน — มันจับข้อยกเว้นในขั้นตอนใดๆ ใน JavaScript — .catch() Dart ยังมี try/await/catch ภายในฟังก์ชัน async สำหรับการกู้คืนข้อผิดพลาด ให้ใช้ .catchError() พร้อมกับการคืนค่าเริ่มต้นหรือ Future ใหม่
Promise.all รับอาเรย์ของ promises และคืนค่า Promise เดียวที่แก้ปัญหาด้วยอาเรย์ของผลลัพธ์ promises ทั้งหมดทำงานพร้อมกัน — ซึ่งเร่งการดำเนินการอิสระ (เช่น การโหลดหลายไฟล์) หาก promise ใดถูกปฏิเสธ — Promise.all ทั้งหมดจะถูกปฏิเสธด้วยข้อผิดพลาดเดียวกัน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม