مقدمة: ليه async مهم؟
تخيل انك في مطعم وطلبت شاي. المطعم مش هيقف في الطابور ويستنى الشاي ينخلص ليهم علشان يقبلوا طلبك التاني – بالعكس، هيتقبلوا طلبياتك التانية وفي نفس الوقت الشاي بيتحضر في المطبخ.
JavaScript بنفس الفكرة – async هي الطريقة اللي JavaScript تشتغل بيها عمليات طويلة بدون ما توقف البرنامج كله.
الجزء الأول: Callbacks (الطريقة القديمة)
في البداية، كانت JavaScript تستخدم Callbacks – يعني دالة تاخد دالة تانية كمعامل:
function fetchData(callback) {
setTimeout(() => {
callback("البيانات وصلت!");
}, 2000);
}
fetchData((data) => {
console.log(data); // البيانات وصلت!
});
المشكلة: لما تتسلسل عمليات كتير، الكود بيصير معقد جداً (“Callback Hell”):
fetchData(() => {
processData(() => {
saveData(() => {
console.log("خلص!");
});
});
});
بتشوف؟ كل عملية جواة عملية – بتصير متاهة.
الجزء الثاني: Promises (الخطوة الوسيطة)
في 2015 جت Promises – وهي طريقة أنظف شوية:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("البيانات وصلت!");
}, 2000);
});
}
fetchData()
.then((data) => {
console.log(data);
return processData(data);
})
.then((result) => {
console.log(result);
return saveData(result);
})
.catch((error) => {
console.log("في خطأ:", error);
});
أحسن من Callbacks، لكن لسة الكود مش سهل القراية مقارنة بالـ synchronous code.
الجزء الثالث: Async/Await (الطريقة الحديثة) ✨
في 2017، جت async/await – وهي بتخليك تكتب الكود كأنه synchronous، لكنه بيشتغل asynchronously:
async function main() {
try {
const data = await fetchData();
console.log(data);
const result = await processData(data);
console.log(result);
await saveData(result);
console.log("خلص!");
} catch (error) {
console.log("في خطأ:", error);
}
}
main();
بتقول ايه؟ الكود بسيط وواضح ومسهل القراية!
إزاي async/await بتشتغل؟
كلمة async:
كل دالة async بترجع Promise دايماً:
async function greeting() {
return "مرحباً!";
}
greeting().then(msg => console.log(msg)); // "مرحباً!"
كلمة await:
بتوقف تنفيذ الدالة لحد ما الـ Promise تتحل:
async function main() {
console.log("1"); // يطبع فوراً
await new Promise(resolve => setTimeout(resolve, 2000));
console.log("2"); // يطبع بعد 2 ثانية
}
main();
أمثلة عملية حقيقية
مثال 1: جلب البيانات من API
async function getUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.log("خطأ في جلب البيانات:", error);
}
}
getUserData(1);
مثال 2: عمليات متعددة بالتوازي
async function getMultipleUsers(ids) {
// الطريقة البطيئة (متسلسلة):
// const user1 = await fetchUser(ids[0]);
// const user2 = await fetchUser(ids[1]);
// الطريقة السريعة (متوازية):
const users = await Promise.all(
ids.map(id => fetchUser(id))
);
return users;
}
مثال 3: إعادة محاولة (Retry Logic)
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
if (i === retries - 1) throw error;
console.log(`محاولة ${i + 1} فشلت، محاولة مرة تانية...`);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
الأخطاء الشائعة
خطأ 1: نسيان await
// ❌ غلط
async function main() {
const data = fetchData(); // هترجع Promise، مش البيانات
console.log(data); // Promise { <pending> }
}
// ✅ صح
async function main() {
const data = await fetchData(); // هتستنى البيانات
console.log(data); // البيانات فعلاً
}
خطأ 2: عدم التعامل مع الأخطاء
// ❌ خطر - لو حصل error، البرنامج قد يتوقف
async function main() {
const data = await fetchData();
}
// ✅ آمن - بنتعامل مع الأخطاء
async function main() {
try {
const data = await fetchData();
} catch (error) {
console.log("حصلت مشكلة:", error);
}
}
خطأ 3: operations متسلسلة بدل متوازية
// ❌ بطيء - كل عملية تستنى التانية
async function slow() {
const data1 = await fetchData(1); // 2 ثانية
const data2 = await fetchData(2); // 2 ثانية
// المجموع = 4 ثواني
}
// ✅ سريع - العمليات متوازية
async function fast() {
const [data1, data2] = await Promise.all([
fetchData(1),
fetchData(2)
]);
// المجموع = 2 ثانية
}
نصائح ذهبية
- استخدم try/catch دايماً – علشان تتعامل مع الأخطاء بشكل آمن
- استخدم Promise.all لـ parallel operations – لو العمليات مش معتمدة على بعضها
- لا تستخدم async في الحلقات بدون تفكير – قد تبطيء الأداء
- async functions ترجع Promise دايماً – حتى لو ما كتبت return
- استخدم await في async functions فقط – ما تقدرش تستخدم await في دالة عادية
الخلاصة
- Callbacks قديمة وتسبب كود معقد
- Promises أفضل لكن لسة معقدة
- Async/Await الطريقة الحديثة والأنظف
استخدم async/await في كل الحالات الحديثة – الكود بيصير أسهل وأوضح وأأمن.
سؤال ليك: إيه آخر عملية async عملتها في كودك وواجهت فيها مشكلة؟ 😉
