Promise.allSettled بالعربي: خلّي الصفحة تكمل رغم فشل API
لو صفحة المنتج عندك بتكسر كلها عشان API واحد وقع، المقال ده هيخليك تعرض البيانات المتاحة وتفصل الفشل بدل ما تعاقب المستخدم على خدمة واحدة.
مستوى القارئ: متوسط
المشكلة باختصار
افترض إن صفحة منتج بتجيب السعر، التقييمات، والمخزون من 3 endpoints مختلفة. السعر بيرجع في 120ms، المخزون في 160ms، لكن reviews API بيعمل timeout بعد 900ms. مع Promise.all، فشل reviews بيرفض العملية كلها. النتيجة: صفحة فاضية أو error عام رغم إن عندك بيانات كفاية تعرضها.
الطريقة دي بتفشل في الواجهات اللي تقبل partial data. بدل ما توقف الصفحة كلها، الأفضل تسأل كل promise: نجحت ولا فشلت؟ هنا يظهر دور Promise.allSettled.
الفكرة بمثال واضح
ركز في المثال ده. عندك فريق بيجهز طلب: شخص جاب السعر، شخص جاب حالة المخزون، وشخص فشل يجيب التقييمات. هل تلغي الطلب كله؟ غالبًا لا. تعرض السعر والمخزون، وتكتب مكان التقييمات: غير متاحة مؤقتًا.
بالظبط ده اللي بيعمله Promise.allSettled. هو لا يرمي exception لمجرد إن promise واحدة فشلت. هو يرجع array فيها نتيجة كل promise: fulfilled ومعاها value، أو rejected ومعاها reason.
مثال JavaScript قابل للنسخ
الافتراض إن عندك واجهة متجر، وكل endpoint مستقل. لو التقييمات فشلت، الصفحة تفضل قابلة للاستخدام.
async function loadProductPage(productId) {
const requests = [
fetch(`/api/products/${productId}/price`).then(r => r.json()),
fetch(`/api/products/${productId}/reviews`).then(r => r.json()),
fetch(`/api/products/${productId}/stock`).then(r => r.json()),
];
const [priceResult, reviewsResult, stockResult] = await Promise.allSettled(requests);
return {
price: priceResult.status === "fulfilled" ? priceResult.value : null,
reviews: reviewsResult.status === "fulfilled" ? reviewsResult.value : [],
stock: stockResult.status === "fulfilled" ? stockResult.value : { available: false },
warnings: [priceResult, reviewsResult, stockResult]
.map((result, index) => ({ result, index }))
.filter(item => item.result.status === "rejected")
.map(item => `request_${item.index}_failed`),
};
}في سيناريو واقعي، صفحة فيها 3 أقسام. مع Promise.all وفشل request واحد، المعروض يساوي 0 أقسام. مع Promise.allSettled، ممكن تعرض 2 من 3 أقسام. الرقم هنا بسيط لكنه مهم: بدل 0% من الصفحة، تعرض حوالي 66% من المحتوى المفيد.