أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
البرمجة بالعربي

Promise.all ضد Promise.allSettled: الفرق اللي بيكسر الـ production

📅 ١٩ أبريل ٢٠٢٦⏱ 4 دقائق قراءة
Promise.all ضد Promise.allSettled: الفرق اللي بيكسر الـ production

لو عندك دالة بتعمل 5 طلبات HTTP متوازية، واحد منهم فشل، الـ function كلها بترمي خطأ وكل النتائج التانية بتضيع. ده مش bug في الكود، ده اختيار غلط بين Promise.all و Promise.allSettled.

Promise.all ضد Promise.allSettled: الفرق بالظبط

المشكلة باختصار

الاتنين بياخدوا array من promises ويشغّلوهم بالتوازي. الفرق الحقيقي في سياسة الفشل: Promise.all بترفض فورًا أول ما أي promise يفشل، وبترجع reason بتاع أول فشل بس. Promise.allSettled بتستنى الكل ينتهي، وبترجع array فيه نتيجة كل promise سواء نجح أو فشل. الفرق ده بيحدد هل المستخدم هيشوف data ناقصة ولا شاشة فاضية.

كود JavaScript يعرض Promise.all و Promise.allSettled جنب بعض على شاشة محرر

اللي بيحصل فعلاً في كل واحد

Promise.all بتتصرف fail-fast: أول rejection بيحوّل الـ promise الراجعة لحالة rejected، والباقي لسه شغّال لكن نتيجته بترمى. ركز: الطلبات الباقية مش بتتلغى تلقائيًا، الـ network request لسه ماشي، إنت بس مش هتشوف نتيجته. لو عايز تلغي فعلاً، محتاج AbortController يدوي.

Promise.allSettled بتستنى كل promise يوصل لحالة settled (fulfilled أو rejected). بترجع array من objects، كل object فيه status و value أو reason:

JavaScript
[
  { status: "fulfilled", value: { id: 1 } },
  { status: "rejected",  reason: Error("timeout") },
  { status: "fulfilled", value: { id: 3 } }
]

سيناريو واقعي بيحصل كل أسبوع

dashboard بيعرض بيانات من 4 مصادر: user profile، notifications، billing، analytics. لو استخدمت Promise.all وخدمة billing وقعت لحظة التحميل، المستخدم شاف شاشة فاضية بدل ما يشوف بياناته الأساسية وplaceholder بسيط مكان الـ billing. ده bug حقيقي بيتكرر في production لأن المبرمج اختار الـ primitive الغلط.

الحل العملي بـ Promise.allSettled:

JavaScript
async function loadDashboard(userId) {
  const results = await Promise.allSettled([
    fetch(`/api/profile/${userId}`).then(r => r.json()),
    fetch(`/api/notifications/${userId}`).then(r => r.json()),
    fetch(`/api/billing/${userId}`).then(r => r.json()),
    fetch(`/api/analytics/${userId}`).then(r => r.json()),
  ]);

  const pick = (i, fallback) =>
    results[i].status === "fulfilled" ? results[i].value : fallback;

  return {
    profile:       pick(0, null),
    notifications: pick(1, []),
    billing:       pick(2, null),
    analytics:     pick(3, null),
  };
}

كل خدمة فشلت بتدي fallback مفهوم للـ UI، والمستخدم بيكمل شغله. الـ logging للفشل بيروح لـ Sentry أو أي observability tool، مش للمستخدم.

تمثيل بصري لعدة طلبات HTTP متوازية تنتهي بنتائج مختلفة بعضها ناجح وبعضها فاشل

الأرقام: إيه الفرق فعلاً في الأداء

في قياس بسيط على 4 طلبات متوازية، متوسط latency كل واحد 180ms، وواحد منهم بيعمل timeout بعد 3 ثواني: Promise.all بترجع بعد ~180ms لو مفيش فشل، وبترمي خطأ بعد 3 ثواني لو فيه فشل. Promise.allSettled بتستنى الـ 3 ثواني كاملة دايمًا في حالة الفشل. التكلفة: ثواني زيادة في worst case. المكسب: مفيش بيانات بتضيع، ومفيش حاجة اسمها "كل حاجة فشلت" من طلب واحد.

الحل لمشكلة الانتظار: حط timeout صريح على كل fetch بـ AbortController. كده أسوأ حالة = الـ timeout اللي إنت حاطه (مثلًا 2 ثانية)، مش زمن timeout الخدمة البايظة.

JavaScript
function fetchWithTimeout(url, ms = 2000) {
  const ctrl = new AbortController();
  const t = setTimeout(() => ctrl.abort(), ms);
  return fetch(url, { signal: ctrl.signal })
    .finally(() => clearTimeout(t));
}

trade-offs لازم تحطها في الحسبة

  • زمن الاستجابة: allSettled بيتحكم فيها أبطأ promise دايمًا. بدون timeout صريح، خدمة واحدة بايظة ممكن تخلي الـ dashboard يفضل loading 30 ثانية.
  • التعامل مع الأخطاء: allSettled مش بترفع exception تلقائيًا. لازم تفحص status يدويًا، وإلا هتفاجأ بـ undefined في الـ UI ومفيش log للفشل.
  • الـ type safety: في TypeScript النوع هو PromiseSettledResult<T> اللي هو union بين PromiseFulfilledResult و PromiseRejectedResult. كل قراءة لـ value محتاجة type guard على status.

متى لا تستخدم Promise.allSettled

لو كل الطلبات شرط لنجاح العملية، فـ Promise.all هي الصح. مثال: ترنزاكشن مالية بتتطلب 3 تأكيدات، فشل أي واحد = ترجع العملية كلها. كمان في parallel writes على قاعدة بيانات، لو مشيت بعد فشل جزئي هتخلق data inconsistency. القاعدة: لو ما تقدرش تكمل بنتيجة ناقصة، استخدم all، مش allSettled.

الافتراضات

الشرح ده مبني على بيئة تدعم ES2020 (Node 12.9+، كل المتصفحات الحديثة من 2020). لو Node عندك أقدم من كده، هتحتاج polyfill أو ترقية. الأرقام في قسم الأداء بتفترض طلبات IO مستقلة مش CPU-bound work، ومفيش rate limiting مفاجئ من أي خدمة.

الخطوة التالية

افتح ملف فيه Promise.all في مشروعك دلوقتي. اسأل سؤال واحد: لو طلب واحد فشل، هل المستخدم محتاج النتيجة الكاملة، ولا كل طلب مستقل؟ لو الإجابة "كل طلب مستقل"، حوّلها لـ allSettled مع timeout على كل fetch. لو "كل أو لا شيء"، سيبها زي ما هي وضيف log واضح للفشل.

مصادر

  • MDN — Promise.all()
  • MDN — Promise.allSettled()
  • GreatFrontend — How is Promise.all() different from Promise.allSettled()?
  • MDN — AbortController

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة