الإستدعاء اللاحق في لغة JavaScript
أهلاً بك! اليوم بنتكلم عن مفهوم أساسي ومهم جداً في JavaScript وهو الـ Callback. الموضوع بسيط ومباشر، ويلا نبدأ.
ما هو الـ Callback؟
بكل بساطة، الـ Callback هي دالة (Function) بنمررها كـ argument لدالة ثانية، وهذي الدالة الثانية بتستدعيها (تنفذها) في وقت لاحق. يعني كأنك تقول لدالة: "إذا خلصتي شغلك، سوي هذي الشغلة الثانية اللي أعطيتك إياها".
ليه نحتاج الـ Callback؟
السبب الرئيسي لانتشار الـ Callbacks هو التعامل مع العمليات غير المتزامنة (Asynchronous Operations). في JavaScript، كثير من العمليات ما تتم بشكل فوري، مثل:
- تحميل بيانات من سيرفر (API calls).
- قراءة ملفات.
- التعامل مع الأحداث (Events) زي ضغط زر.
- المؤقتات الزمنية (
setTimeout,setInterval).
لو كانت هذه العمليات تتم بشكل متزامن (Synchronous) وتنتظرها JavaScript تخلص، كان المتصفح بيعلق وما تقدر تسوي أي شيء ثاني. الـ Callbacks تخلينا نقول: "ابدأ هذي العملية، ولما تخلص، نادي الدالة الفلانية عشان تكمل الشغل".
مثال بسيط ومباشر
خلونا نشوف مثال على دالة بسيطة تستقبل Callback:
function sayHello(name, callback) {
console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">أهلاً بك يا ${name}!</code>);
// الآن نستدعي الدالة اللي مرت لنا كـ callback
callback();
}
function goodBye() {
console.log('مع السلامة!');
}
// نستدعي sayHello ونمرر لها goodBye كـ callback
sayHello('أحمد', goodBye);
// Output:
// أهلاً بك يا أحمد!
// مع السلامة!
في هذا المثال، goodBye هي دالة الـ Callback. استدعيناها داخل sayHello بعد ما طبعنا رسالة الترحيب.
الـ Callbacks في العمليات غير المتزامنة
أشهر مثال على الـ Callbacks في العمليات غير المتزامنة هو الدالة setTimeout، اللي بتنفذ دالة معينة بعد فترة زمنية محددة:
function loadData(callback) {
console.log('جاري تحميل البيانات...');
// محاكاة عملية تحميل بيانات تستغرق ثانيتين
setTimeout(() => {
const data = { id: 1, name: 'Sample Data', status: 'loaded' };
console.log('تم تحميل البيانات.');
// بعد انتهاء التحميل، نستدعي الـ callback ونمرر لها البيانات
callback(data);
}, 2000); // ثانيتين
}
function processData(info) {
console.log('تم معالجة البيانات بنجاح:', info);
}
// نستدعي loadData ونمرر لها processData كـ callback
loadData(processData);
// Output (بعد ثانيتين):
// جاري تحميل البيانات...
// تم تحميل البيانات.
// تم معالجة البيانات بنجاح: { id: 1, name: 'Sample Data', status: 'loaded' }
ملاحظة: هنا
processDataهي الـcallbackاللي بتشتغل بعد ماloadDataتخلص شغلها asynchronously. دالةsetTimeoutنفسها بتأخذcallbackكأول argument.
لاحظ كيف أن processData ما اشتغلت إلا بعد مرور ثانيتين، وهذا دليل على أنها انتظرت loadData تخلص شغلها. هذا هو جوهر التعامل مع العمليات غير المتزامنة.
مشكلة الـ Callback Hell (باختصار)
مع أن الـ Callbacks قوية ومفيدة، لكن لما يكون عندك عمليات غير متزامنة كثيرة ومتسلسلة، ممكن الكود يصير معقد وصعب القراءة والمتابعة، وهذا اللي نسميه Callback Hell أو Pyramid of Doom (هرم الموت) بسبب الشكل الهرمي اللي يتخذه الكود:
// تخيل هذا السيناريو
getData(function(data) {
processData1(data, function(result1) {
processData2(result1, function(result2) {
processData3(result2, function(finalResult) {
console.log('Finished all steps with:', finalResult);
});
});
});
});
ملاحظة: هذه المشكلة أدت لظهور حلول أفضل وأكثر تنظيمًا للتعامل مع العمليات غير المتزامنة في JavaScript، مثل
PromisesوAsync/Await، اللي خلت الكود أسهل في القراءة والصيانة.
خلاصة
الـ Callback هي أداة أساسية وضرورية لفهم كيفية عمل JavaScript مع العمليات غير المتزامنة. فهمك لها بيفتح لك الباب لفهم مفاهيم أكثر تقدماً زي الـ Promises والـ Async/Await اللي بنيت على نفس المبدأ. استمر في الممارسة، والموضوع بيصير سهل جداً!