الهدف
بنهاية الدرس تفهم ليش JavaScript single-threaded وكيف async/await يحل المشكلة، تكتب async function بـ try/catch صحيح، وتشغّل عمليتين بالتوازي بـ Promise.all.
ليش هذا الحين؟
ترى كل شي مهم في الـ app هو async — قراءة بيانات من قاعدة البيانات، جلب ملف، إرسال email، استدعاء external API. لو ما تفهم async، ما تقدر تكتب app حقيقي. والمشكلة إن الـ async/await شكلها بسيطة بس وايد من الناس يستخدمونها غلط — ينسون await، ما يعالجون الأخطاء، أو يشغّلون عمليات بالتسلسل وهي تقدر تشتغل بالتوازي. هالدرس يصلح كل هذا.
الفكرة
JavaScript = single-threaded. يعني هو يشتغل على خيط واحد بس — تعليمة واحدة في كل مرة. لو شغّلت عملية تاخذ وقت (مثلا database query) بدون async، الـ thread ينتظر ويتجمد — الـ UI ما يستجيب لأي click أو حركة.
الحل: Non-blocking async.
JavaScript يبدأ العملية ويروح يكمل شغل ثاني. لما العملية تخلص، يرجع يكمل.
Blocking (سيء):
[DB Query] → انتظار... → انتظار... → [تم] → [كود يتابع]
(الـ UI مجمّد طول هذي الفترة)
Non-blocking (صح):
[ابدأ DB Query] → [كود يكمل يشتغل] → [DB رجع] → [تابع]
(الـ UI شغّال طول الوقت)
التطور التاريخي:
الـ Callbacks جت أولا — وسبّبت "callback hell":
// callback hell — قبيح وصعب تتبعه
getUser(id, (user) => {
getPosts(user.id, (posts) => {
getComments(posts[0].id, (comments) => {
// ثلاث طبقات — والموضوع يزيد
})
})
})
بعدين Promises:
// أحسن بس لسه verbose
getUser(id)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.catch(err => console.error(err))
الحين async/await — تكتب async كأنه sync:
// واضح ونظيف
async function loadData() {
try {
const user = await getUser(id)
const posts = await getPosts(user.id)
const comments = await getComments(posts[0].id)
} catch (err) {
console.error(err)
}
}
القاعدة: كل await لازم يكون داخل async function. وكل async function ترجع Promise تلقائيا.