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 — معالجة متسلسلة للعمليات غير المتزامنة دون callbacks متداخلة
  • Future في Dart — أساس async/await ومكتبات dio و http و shelf
  • Future/Promise — بديل لنمط callback وأساس لصيغة async/await

ما هو Future/Promise؟

Future/Promise هو زوج من الكائنات المترابطة التي تقسم النتيجة غير المتزامنة إلى دورين. Promise يمكنه كتابة النتيجة (resolve) أو خطأ (reject). Future يمكنه فقط قراءتها — من خلال callbacks (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 يأخذ منفذًا — دالة مع معاملات resolve و reject. الطرق الثابتة Promise.all و Promise.race و Promise.allSettled تسمح بدمج عدة promoses. التطبيقات الحديثة تستخدم صيغة async/await فوق Promise.

كيف يعمل Future

Future يعمل استنادًا إلى event loop — دورة أحداث تعالج العمليات غير المتزامنة دون حظر الخيط الرئيسي. عند استدعاء دالة غير متزامنة (مثل http.get)، فإنها تعيد Future فورًا. الطلب الفعلي يُنفذ في الخلفية، بينما يستمر event loop في معالجة الأحداث الأخرى. بعد اكتمال العملية، ينتقل Future إلى حالة resolved ويُستدعى then.

Event loop هو الآلية الرئيسية التي بُنيت عليها Dart و JavaScript. يحافظ event loop على قائمتين: قائمة المهام الصغيرة (مهام قصيرة، تُنفذ قبل الحدث التالي) وقائمة الأحداث (أحداث IO، مؤقتات). Future.then يضع callback في قائمة المهام الصغيرة، 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 ينتظر اكتمال جميع promoses الممررة ويعيد مصفوفة من النتائج بنفس الترتيب. إذا فشل promise بخطأ — ينتقل Promise.all بأكمله إلى rejected. Promise.race يعيد نتيجة أول promise مكتمل (نجاح أو خطأ). Promise.allSettled ينتظر جميع promoses بغض النظر عن الأخطاء — يعيد حالة كل منها.

Chaining (السلسلة) هي الميزة الرئيسية لـ Promise على callbacks. كل .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"))

المثال الثاني — دمج عدة Futures مع 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 يؤدي إلى التداخل (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 لإدارة مجموعة الخيوط ويدعم التركيب عبر 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 المستند إلى callbacks وسلاسل 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 هو monad. 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++ متعددة الخيوط.

أنماط Future

عند تصميم APIs تعيد Futures، اتبع قاعدة المصدر الوحيد للحقيقة: كل طلب غير متزامن يُنشأ مرة واحدة ويُخزن مؤقتًا عبر Future.memoize. إذا طلب مكونان نفس البيانات، يتلقّيان نفس Future — هذا يمنع الطلبات المكررة. للمهلة الزمنية، استخدم Future.timeout (Dart) أو Promise.race مع مهلة زمنية لضمان اكتمال العملية غير المتزامنة ضمن فاصل زمني محدد.

نمط Retry في Future يُنفذ عبر سلسلة تكرارية: عند خطأ في catch، تُستدعى نفس الدالة غير المتزامنة مع تأخير. Exponential backoff يزيد الفاصل بين المحاولات: 1 ثانية — 2 ثانية — 4 ثوان — حتى 30 ثانية كحد أقصى. في Dart يتم تغليف هذا في extension على Future: future.retry(maxRetries: 3, delay: Duration(seconds: 1)). في Scala، Future.zip يدمج نتيجتين مستقلتين في tuple — بديل لـ Promise.all لـ Futureين. الإلغاء غير مدعوم في Futures القياسية، لكنه يُنفذ عبر 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 يأخذ مصفوفة من promoses ويعيد Promise واحدًا يتحلل إلى مصفوفة من النتائج. جميع promoses تُشغل بالتوازي — هذا يسرع العمليات المستقلة (مثل تحميل عدة ملفات). إذا تم رفض أي promise — يُرفض Promise.all بأكمله بنفس الخطأ.

الخلاصة

  • Future/Promise — نمط برمجة غير متزامنة مع عقد لقيمة واحدة
  • Future — حاوية للقراءة فقط لقراءة نتيجة عملية
  • Promise — عقد للكتابة فقط يملأ Future عبر resolve/reject
  • سلاسل then — معالجة مسطحة لخطوات غير متزامنة دون callback hell
  • async/await — سكر نحوي فوق Future، يجعل الكود خطيًا
  • Promise.all — تنفيذ متوازي لعدة عمليات غير متزامنة
  • للقيم المتعددة عبر الزمن، استخدم Stream أو Observable، ليس Future

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا