البرومس في لغة JavaScript
أهلاً بك! اليوم راح نتكلم عن البرومس (Promises) في JavaScript، ليش مهمة وكيف تستخدمها عشان تتعامل مع العمليات غير المتزامنة (asynchronous operations) بطريقة نظيفة ومفهومة بدل ما نطيح في دوامة الـ "Callback Hell".
إيش هو البرومس (Promise)؟
بكل بساطة، البرومس هو كائن (object) يمثل القيمة النهائية لعملية غير متزامنة. تخيل إنك طلبت قهوة من مقهى. الطلب هذا هو عملية غير متزامنة. البرومس هنا زي "إيصال الطلب" اللي يعطيك إياه الكاشير. الإيصال هذا ممكن يكون في 3 حالات:
pending: الطلب لسه قيد التجهيز (البرومس لسه ما خلص).fulfilled(أوresolved): القهوة جاهزة واستلمتها (العملية نجحت والبرومس انتهى بنجاح).rejected: المقهى اعتذر وما قدر يسوي طلبك (العملية فشلت والبرومس انتهى بفشل).
ملاحظة: البرومس يضمن لك إن العملية غير المتزامنة هذي بتخلص في المستقبل، يا بنجاح يا بفشل، وما راح ترجع لحالة
pendingمرة ثانية بعد ما تتغير.
كيف تسوي برومس؟
تسوي برومس جديد باستخدام الكلمة المفتاحية new Promise، وتعطيها دالة (executor function) تاخذ دالتين كـ arguments: resolve و reject.
const myFirstPromise = new Promise((resolve, reject) => {
// هنا تحط الكود غير المتزامن حقك
const success = true; // افترض إن العملية نجحت
if (success) {
setTimeout(() => {
resolve("تم إنجاز المهمة بنجاح!"); // نداء resolve لما العملية تنجح
}, 2000); // محاكاة عملية تأخذ ثانيتين
} else {
reject("فشلت المهمة!"); // نداء reject لما العملية تفشل
}
});
في المثال اللي فوق، لو success كانت true، بعد ثانيتين راح نستدعي resolve ونمرر لها رسالة النجاح. لو كانت false، راح نستدعي reject.
كيف تتعامل مع البرومس؟
عشان تتعامل مع نتيجة البرومس، تستخدم الدوال then()، catch()، و finally().
then() - للنجاح
تستخدم then() عشان تنفذ كود معين لما البرومس ينجح (يصير fulfilled).
myFirstPromise.then((message) => {
console.log("نجاح:", message); // "نجاح: تم إنجاز المهمة بنجاح!"
});
catch() - للفشل
تستخدم catch() عشان تتعامل مع الأخطاء لما البرومس يفشل (يصير rejected).
const failedPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("خطأ: تعذر الوصول إلى البيانات!");
}, 1500);
});
failedPromise.catch((error) => {
console.error("فشل:", error); // "فشل: خطأ: تعذر الوصول إلى البيانات!"
});
finally() - دائماً
تنفذ finally() سواء نجح البرومس أو فشل. غالباً تستخدم لتنظيف الموارد أو إخفاء مؤشرات التحميل.
myFirstPromise
.then((message) => {
console.log(message);
})
.catch((error) => {
console.error(error);
})
.finally(() => {
console.log("البرومس انتهى، سواء بنجاح أو فشل.");
});
سلسلة البرومس (Promise Chaining)
البرومس يخليك تسوي سلسلة من العمليات غير المتزامنة بشكل مرتب. كل then() ترجع برومس جديد، وهذا يسمح لك تستدعي then() أخرى بعدها.
function fetchData(dataId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">تم جلب البيانات ${dataId}</code>);
}, 1000);
});
}
fetchData(1)
.then((result1) => {
console.log(result1); // "تم جلب البيانات 1"
return fetchData(2); // نرجع برومس جديد
})
.then((result2) => {
console.log(result2); // "تم جلب البيانات 2"
return fetchData(3);
})
.then((result3) => {
console.log(result3); // "تم جلب البيانات 3"
console.log("جميع البيانات تم جلبها بنجاح!");
})
.catch((error) => {
console.error("حدث خطأ في سلسلة البرومس:", error);
});
نصيحة: دائماً حط
catch()في نهاية السلسلة عشان تمسك أي أخطاء ممكن تصير في أي خطوة.
أدوات مساعدة: Promise.all() و Promise.race()
Promise.all()
تستخدم لما يكون عندك مجموعة من البرومس وتبغى تنتظرها كلها تخلص بنجاح. لو واحد منها فشل، Promise.all() كلها تفشل.
const promise1 = Promise.resolve(3);
const promise2 = 42; // قيمة عادية تعتبر resolve
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // [3, 42, "foo"] بعد 100 ملي ثانية
});
Promise.race()
تستخدم لما يكون عندك مجموعة من البرومس، وتبغى أول واحد يخلص (سواء بنجاح أو فشل) هو اللي يحدد النتيجة النهائية.
const p1 = new Promise((resolve) => setTimeout(resolve, 500, 'الأول'));
const p2 = new Promise((resolve) => setTimeout(resolve, 100, 'الثاني'));
Promise.race([p1, p2]).then((value) => {
console.log(value); // "الثاني" (لأنها خلصت أسرع)
});
الخلاصة
البرومس هي طريقة رائعة للتعامل مع العمليات غير المتزامنة في JavaScript بشكل منظم ومقروء، وتساعدك تتجنب تعقيدات الـ "Callback Hell". افهم حالاتها (pending, fulfilled, rejected) وكيف تستخدم then(), catch(), finally()، وبتشوف كيف الكود حقك بيصير أنظف وأسهل للصيانة.