Promise هو كائن في JavaScript يمثل مهمة غير متزامنة قد تكتمل في المستقبل. يشبه الأمر وعدًا: “أعدك بإرجاع النتيجة لك عند اكتمال المهمة”. يمكن أن يكون Promise في إحدى الحالات الثلاث التالية:
- قيد الانتظار (Pending): الحالة الأولية، لم تكتمل المهمة أو تم رفضها بعد.
- مكتمل (Fulfilled): اكتملت المهمة بنجاح.
- مرفوض (Rejected): فشلت المهمة.
لماذا نستخدم Promise؟
قبل ظهور Promise، كانت الدوال Callback تُستخدم لمعالجة العمليات غير المتزامنة. ومع ذلك، فإن التداخل المتعدد للدوال Callback يؤدي إلى “Callback Hell”، مما يجعل الكود صعب القراءة والصيانة. يحل Promise هذه المشكلة من خلال توفير طريقة كتابة تعليمات برمجية واضحة وخطية، مما يُسهل إدارة المهام غير المتزامنة ومعالجة الأخطاء.
دليل استخدام Promise في JavaScript
إنشاء Promise
لإنشاء Promise، ستستخدم new Promise
، مع تمرير دالة executor تحتوي على معلمتين هما resolve
و reject
. يتم استدعاء resolve
عند اكتمال Promise بنجاح، ويتم استدعاء reject
عند رفض Promise.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('نجاح!');
} else {
reject('فشل!');
}
}, 1000);
});
في هذا المثال، بعد ثانية واحدة، سيتم إكمال Promise بنتيجة “نجاح!” أو رفضه بنتيجة “فشل!”.
معالجة النتائج باستخدام .then() و .catch()
لاستلام النتيجة من Promise، يمكنك استخدام الدالتين .then()
و .catch()
. يتم استدعاء .then(onFulfilled)
عند اكتمال Promise، ويتم استدعاء .catch(onRejected)
عند رفض Promise.
promise
.then((result) => {
console.log(result); // "نجاح!"
})
.catch((error) => {
console.error(error); // "فشل!"
});
تسلسل Promises (Chaining Promises)
يمكنك تسلسل Promises عن طريق إرجاع Promise داخل .then()
.
firstPromise()
.then((result1) => {
return secondPromise(result1);
})
.then((result2) => {
console.log(result2);
})
.catch((error) => {
console.error(error);
});
استخدام Promise.all
Promise.all
يسمح لنا بتشغيل عدة Promises بالتوازي واستلام النتائج عندما تكتمل جميعها.
const promise1 = fetchData1();
const promise2 = fetchData2();
Promise.all([promise1, promise2])
.then(([result1, result2]) => {
console.log(result1, result2);
})
.catch((error) => {
console.error(error);
});
عليك دائمًا معالجة الأخطاء باستخدام .catch()
. إذا تجاهلت ذلك، فقد لا يتم اكتشاف الأخطاء وتسبب مشاكل يصعب تصحيحها.
دليل استخدام Promise في React
في React، غالبًا ما نحتاج إلى تنفيذ مهام غير متزامنة مثل استدعاء API للحصول على البيانات. يساعد استخدام Promise في إدارة هذه المهام بكفاءة.
استخدام fetch API مع Promise
fetch
هي واجهة برمجة تطبيقات (API) مدمجة في JavaScript للحصول على البيانات، وهي تُرجع Promise.
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error('خطأ:', error);
});
في هذا المثال، نستدعي API على الرابط: https://jsonplaceholder.typicode.com/users
للحصول على قائمة المستخدمين.
استخدام Promise, useEffect في المكون
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
})
.catch((error) => {
console.error('خطأ:', error);
});
}, []);
return (
<div>
{users ? (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
) : (
<div>جاري التحميل...</div>
)}
</div>
);
}
export default UserList;
useEffect
مع dependencies فارغة[]
سيتم تشغيلها مرة واحدة فقط عند تحميل المكون.- استخدام
fetch
لاستدعاء API وتحديث الحالةusers
عند استلام النتيجة.
مقارنة Promise و Async/Await
Async/Await هي صيغة جديدة تعتمد على Promise، مما يجعل الكود يبدو أشبه بالكود المتزامن، وأسهل في القراءة والفهم. تستخدم try...catch
لمعالجة الأخطاء وتجنب التداخل المفرط لـ .then()
. ومع ذلك، يتطلب استخدام Async/Await أيضًا فهمًا جيدًا لـ Promise. استخدم Async/Await عندما تريد أن يبدو الكود متزامنًا، وسهل القراءة وتحتاج إلى تنفيذ مهام غير متزامنة بالتسلسل. استخدم Promise عندما تحتاج إلى إدارة مهام متعددة غير متزامنة في وقت واحد وتحتاج إلى استخدام دوال مثل: Promise.all
، Promise.race
.