Future/Promise — چیست، محاسبات ناهمزمان و برنامه‌نویسی

نویسنده: IT Sectr منتشر شده: 2026-03-17 زمان مطالعه: 9 دقیقه

Future/Promise یک الگوی برنامه‌نویسی ناهمزمان است که ظرفی برای نتیجه عملیات هنوز تکمیل‌نشده ارائه می‌دهد. به گفته Dart Documentation, 2025، Future نتیجه فقط-خواندنی محاسبات به تعویق افتاده است، Promise یک قرارداد فقط-نوشتنی است که این نتیجه را پر می‌کند. Future در Dart, Java, Scala و C++ برای زنجیره‌های then/catch استفاده می‌شود.

نکات اصلی

  • Future — ظرف فقط-خواندنی برای نتیجه ناهمزمان قابل دسترس در آینده
  • Promise — پرکننده فقط-نوشتنی که نتیجه را می‌پذیرد و به Future منتقل می‌کند
  • زنجیره‌های then — پردازش ترتیبی عملیات ناهمزمان بدون callbackهای تودرتو
  • Future در Dart — پایه async/await و کتابخانه‌های dio, http, shelf
  • Future/Promise — جایگزینی برای الگوی callback و پایه نحو async/await

Future/Promise چیست؟

Future/Promise یک جفت شیء مرتبط است که نتیجه ناهمزمان را به دو نقش تقسیم می‌کند. Promise می‌تواند نتیجه (resolve) یا خطا (reject) را بنویسد. Future فقط می‌تواند آن را بخواند — از طریق callback (then, catchError) یا از طریق await. این تقسیم تضمین می‌کند که مصرف‌کننده نمی‌تواند نتیجه را تغییر دهد، فقط از آن استفاده کند.

Future در Dart

زبان Dart از Future به عنوان مکانیزم اصلی ناهمزمانی استفاده می‌کند. Future<T> — قراردادی برای دریافت مقدار نوع T در آینده. Future می‌تواند در یکی از سه حالت باشد: unresolved (عملیات در حال اجرا)، resolved with value (با موفقیت تکمیل شد) یا resolved with error (با خطا تکمیل شد). پس از انتقال به حالت resolved، Future تغییر نمی‌کند.

Promise در JavaScript

Promise در JavaScript مشابه Future در Dart است، اما با API غنی‌تر. Promise یک executor — تابعی با پارامترهای resolve و reject دریافت می‌کند. متدهای ایستا Promise.all, Promise.race, Promise.allSettled امکان ترکیب چند promise را فراهم می‌کنند. برنامه‌های مدرن از نحو async/await بر پایه Promise استفاده می‌کنند.

Future چگونه کار می‌کند

Future بر اساس event loop — چرخه رویدادی که عملیات ناهمزمان را بدون مسدود کردن نخ اصلی پردازش می‌کند — کار می‌کند. وقتی یک تابع ناهمزمان فراخوانی می‌شود (مثلاً http.get)، بلافاصله Future برمی‌گرداند. درخواست واقعی در پس‌زمینه اجرا می‌شود و event loop به پردازش رویدادهای دیگر ادامه می‌دهد. پس از اتمام عملیات، Future به حالت resolved می‌رود و then فراخوانی می‌شود.

Event loop مکانیزم کلیدی است که Dart و JavaScript بر آن ساخته شده‌اند. Event loop دو صف را نگه می‌دارد: microtask queue (وظایف کوتاه که قبل از رویداد بعدی اجرا می‌شوند) و event queue (رویدادهای IO، تایمرها). Future.then callback را در microtask queue قرار می‌دهد، Future.microtask — اجرای اولویت‌دار قبل از فریم بعدی.

زنجیره‌های then() امکان پردازش ترتیبی نتایج عملیات ناهمزمان بدون callback hell را فراهم می‌کنند. هر then() نتیجه مرحله قبلی را دریافت می‌کند و یک Future جدید برمی‌گرداند. catchError() در انتهای زنجیره هر خطایی را که در هر مرحله رخ داده است پردازش می‌کند. این کار کد ناهمزمان را خطی و خوانا می‌کند.

CompletableFuture در Java

در 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 و قرارداد ناهمزمانی

Promise قراردادی با یکی از سه حالت است: pending (در انتظار)، fulfilled (با موفقیت تکمیل شد) یا rejected (با خطا تکمیل شد). پس از انتقال به حالت fulfilled یا rejected، Promise هرگز تغییر نمی‌کند — این تغییرناپذیری نتیجه را برای تمام مصرف‌کنندگان تضمین می‌کند. متد .then() به صورت ناهمزمان پس از انتقال به هر حالت تکمیل‌شده فراخوانی می‌شود.

Promise.all منتظر اتمام تمام promiseهای ارسال‌شده می‌ماند و آرایه‌ای از نتایج را به همان ترتیب برمی‌گرداند. اگر یک promise با خطا تکمیل شود — کل Promise.all به rejected می‌رود. Promise.race نتیجه اولین promise تکمیل‌شده را برمی‌گرداند (موفقیت یا خطا). Promise.allSettled منتظر تمام promiseها بدون توجه به خطاها می‌ماند — وضعیت هر یک را برمی‌گرداند.

Chaining — مزیت کلیدی Promise نسبت به callback. هر .then() یک Promise جدید برمی‌گرداند و امکان ساخت زنجیره‌هایی با طول دلخواه را فراهم می‌کند. خطا در هر حلقه زنجیره تا نزدیک‌ترین .catch() منتشر می‌شود. متد finally() کد را پس از اتمام زنجیره بدون توجه به نتیجه اجرا می‌کند — برای پاکسازی منابع.

نمونه کد Future (Dart)

مثال اول — ایجاد Future از طریق تابع async و پردازش با then/catchError:

dart
Future<String> fetchData() async {
    await Future.delayed(Duration(seconds: 1))
    return "داده‌ها بارگذاری شدند"
}

fetchData()
    .then((result) => print(result))
    .catchError((error) => print("خطا: $error"))

مثال دوم — ترکیب چند Future از طریق Future.wait:

dart
Future<List<String>> loadAll() async {
    final futures = [
        fetchFromApi("/users"),
        fetchFromApi("/posts"),
        fetchFromApi("/comments")
    ]
    final results = await Future.wait(futures)
    return results
}

مثال سوم — Promise در JavaScript با ایجاد دستی و زنجیره then:

js
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("انجام شد")
    }, 1000)
})

promise
    .then(value => console.log(value))
    .catch(err => console.error(err))

Future در برابر سایر الگوهای ناهمزمان

Future/Promise با سبک callback تفاوت دارد زیرا یک شیء-قرارداد را برمی‌گرداند به جای اینکه یک تابع برگشتی را به عنوان آرگومان بپذیرد. سبک callback منجر به تودرتو شدن (callback hell) می‌شود، در حالی که Future امکان ساخت زنجیره‌های then() مسطح را فراهم می‌کند. نحو async/await کد با 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 برای مدیریت استخر نخ‌ها استفاده می‌کند و composition را از طریق for-comprehension پشتیبانی می‌کند.

در Dart الگوی Future با JavaScript Promise تفاوت دارد زیرا 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() چند کوروتین را به صورت موازی اجرا می‌کند و فهرستی از نتایج را برمی‌گرداند، مشابه 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 امکان ترکیب ترتیبی چند Future را بدون تودرتو فراهم می‌کند: 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++ در نظر گرفته شود.

الگوهای کار با Future

در طراحی APIهایی که Future برمی‌گردانند، از قانون منبع واحد حقیقت پیروی کنید: هر درخواست ناهمزمان یک بار ایجاد می‌شود و از طریق Future.memoize ذخیره می‌شود. اگر دو مؤلفه داده‌های یکسانی را درخواست کنند، همان Future را دریافت می‌کنند — این از تکرار درخواست‌ها جلوگیری می‌کند. برای timeout از Future.timeout (Dart) یا Promise.race با timeout استفاده کنید تا تضمین کنید عملیات ناهمزمان در بازه تعیین‌شده تکمیل می‌شود.

الگوی Retry در Future از طریق زنجیره بازگشتی پیاده‌سازی می‌شود: در صورت خطا در catch، همان تابع ناهمزمان با تأخیر فراخوانی می‌شود. Exponential backoff فاصله بین تلاش‌ها را افزایش می‌دهد: 1 ثانیه — 2 ثانیه — 4 ثانیه — تا حداکثر 30 ثانیه. در Dart این در extension روی Future محصور می‌شود: future.retry(maxRetries: 3, delay: Duration(seconds: 1)). در Scala Future.zip دو نتیجه مستقل را در یک تاپل ترکیب می‌کند — جایگزینی برای Promise.all برای دو Future. لغو (Cancellation) در Futureهای استاندارد پشتیبانی نمی‌شود، اما از طریق CancellationToken یا AbortController در JavaScript پیاده‌سازی می‌شود.

سوالات متداول

تفاوت بین Future و Promise چیست؟

Future — یک ظرف فقط-خواندنی برای خواندن نتیجه ناهمزمان از طریق then یا await. Promise — یک قرارداد فقط-نوشتنی که مقدار را از طریق resolve() می‌پذیرد و آن را به Future متصل می‌کند. در Dart و JavaScript این مفاهیم ترکیب شده‌اند: Future/Promise یک کلاس است. در Java و Scala آنها جدا هستند.

Future چه تفاوتی با Observable دارد؟

Future یک نتیجه ناهمزمان واحد را نشان می‌دهد — دقیقاً یک مقدار منتشر می‌کند و پایان می‌یابد. Observable (Rx) مقادیر متعددی را در زمان منتشر می‌کند — این یک جریان ناهمزمان است. اگر یک پاسخ HTTP نیاز دارید — از Future استفاده کنید. اگر جریانی از تغییرات پایگاه داده نیاز دارید — از Observable یا Stream استفاده کنید.

async/await چیست و چه رابطه‌ای با Future دارد؟

async/await — شکر نحوی بر روی Future/Promise است. کلمه کلیدی async یک تابع را به عنوان ناهمزمان علامت‌گذاری می‌کند — آن Future برمی‌گرداند. await اجرا را تا تکمیل Future متوقف می‌کند، بدون مسدود کردن نخ. در Dart, JavaScript, Python و C#، async/await جایگزین زنجیره‌های then در بیشتر سناریوها شده است.

چگونه خطاها را در زنجیره Future پردازش کنیم؟

در Dart از .catchError() در انتهای زنجیره استفاده کنید — آن استثناها را در هر مرحله می‌گیرد. در JavaScript — .catch(). در Dart همچنین try/await/catch در داخل توابع async در دسترس است. برای بازیابی پس از خطا از .catchError() با بازگرداندن مقدار پیش‌فرض یا یک Future جدید استفاده کنید.

Promise.all چیست و چه زمانی از آن استفاده کنیم؟

Promise.all آرایه‌ای از promiseها را می‌پذیرد و یک Promise برمی‌گرداند که با آرایه‌ای از نتایج حل می‌شود. همه promiseها به صورت موازی راه‌اندازی می‌شوند — این کار اجرای عملیات مستقل را سرعت می‌بخشد (مثلاً بارگذاری چندین فایل). اگر هر promise رد شود — کل Promise.all با همان خطا رد می‌شود.

خلاصه

  • Future/Promise — الگوی برنامه‌نویسی ناهمزمان با قرارداد برای یک مقدار
  • Future — ظرف فقط-خواندنی برای خواندن نتیجه عملیات
  • Promise — قرارداد فقط-نوشتنی که Future را از طریق resolve/reject پر می‌کند
  • زنجیره‌های then — پردازش مسطح مراحل ناهمزمان بدون callback hell
  • async/await — شکر نحوی بر روی Future، کد را خطی می‌کند
  • Promise.all — اجرای موازی چندین عملیات ناهمزمان
  • برای مقادیر متعدد در زمان از Stream یا Observable استفاده کنید، نه Future

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید