ما هي المزامنة في لغة JavaScript


ما هي المزامنة في لغة JavaScript

خلونا ندخل في الموضوع على طول. لما نتكلم عن المزامنة (Asynchronicity) في JavaScript، إحنا بنتكلم عن قدرة الجافاسكريبت إنها تنفذ مهام متعددة بدون ما تنتظر مهمة تخلص عشان تبدأ الثانية. فكر فيها كأنك بتطلب قهوة في كافيه. لو كان الكافيه متزامن (Synchronous)، الباريستا ما يقدر يبدأ يسوي قهوة للزبون اللي بعدك إلا لما تخلص قهوتك وتدفع وتمشي. أما لو كان غير متزامن (Asynchronous)، الباريستا ياخذ طلبك، ويبدأ يسوي قهوتك، وفي نفس الوقت ياخذ طلب الزبون اللي بعدك ويبدأ يسوي قهوته كمان.

ليش نحتاجها؟

تخيل إنك بتجيب بيانات من سيرفر (مثل API call) أو بتسوي عملية بتاخذ وقت طويل (زي قراءة ملف كبير). لو الجافاسكريبت كانت متزامنة بس، كان المتصفح بيتعلق (freezes) وما تقدر تسوي أي حاجة لحد ما تخلص العملية دي. المزامنة بتخلي الكود بتاعك غير محظور (non-blocking)، يعني تقدر تسوي عمليات طويلة في الخلفية بدون ما توقف واجهة المستخدم (UI) عن الاستجابة.

كيف تشتغل المزامنة في JavaScript؟

الجافاسكريبت نفسها لغة متزامنة وذات خيط واحد (single-threaded synchronous language). إيه ده؟ كيف؟ السر مو في الجافاسكريبت نفسها، بل في البيئة اللي بتشتغل فيها (المتصفح أو Node.js). البيئات دي بتوفر لنا Web APIs (مثل setTimeout، fetch، DOM events) اللي بتشتغل خارج نطاق الجافاسكريبت الرئيسي. فيه مفاهيم أساسية هنا:

  • Call Stack: المكان اللي بيتنفذ فيه الكود بتاعك سطر بسطر.
  • Web APIs: وظائف بتوفرها البيئة (المتصفح) لتنفيذ مهام غير متزامنة.
  • Callback Queue (Task Queue): لما الـ Web API تخلص شغلها، بتحط الـ callback function بتاعها هنا.
  • Event Loop: هو اللي بيراقب الـ Call Stack والـ Callback Queue. لو الـ Call Stack فاضي، الـ Event Loop بياخد أول callback من الـ Callback Queue ويحطه في الـ Call Stack عشان يتنفذ.

أدوات التعامل مع المزامنة

1. Callbacks (الدوال الراجعة)

أبسط طريقة للتعامل مع المزامنة. هي دالة بنمررها لدالة ثانية عشان تتنفذ بعد ما تخلص المهمة الأولى.

ملاحظة: الكولباكس ممكن تؤدي لمشكلة اسمها "Callback Hell" لما يكون عندك كولباكس متداخلة كتير.

مثال:

setTimeout(function() {
    console.log('هذي الرسالة حتظهر بعد ثانيتين');
}, 2000);

console.log('هذي الرسالة حتظهر أولاً');

في المثال ده، console.log('هذي الرسالة حتظهر أولاً') حتتنفذ على طول، وبعد ثانيتين حتتنفذ الدالة اللي داخل setTimeout.

2. Promises (الوعود)

حل أفضل لمشكلة Callback Hell. الـ Promise هو كائن بيمثل نتيجة عملية غير متزامنة ممكن تكون نجحت (fulfilled) أو فشلت (rejected) أو لسه في انتظار (pending).

مثال:

const fetchData = new Promise((resolve, reject) => {
    // محاكاة لعملية جلب بيانات من سيرفر
    setTimeout(() => {
        const success = true; // نفترض إن العملية نجحت
        if (success) {
            resolve('البيانات تم جلبها بنجاح!');
        } else {
            reject('فشل في جلب البيانات.');
        }
    }, 1500);
});

fetchData
    .then(data => {
        console.log(data); // "البيانات تم جلبها بنجاح!"
    })
    .catch(error => {
        console.error(error); // "فشل في جلب البيانات."
    })
    .finally(() => {
        console.log('انتهت عملية جلب البيانات.');
    });

console.log('جاري جلب البيانات...');

هنا، console.log('جاري جلب البيانات...') حتظهر أولاً، وبعدين الـ Promise حيتعامل مع جلب البيانات في الخلفية، ولما يخلص حيتنفذ .then() أو .catch().

3. Async/Await

أحدث وأفضل طريقة للتعامل مع الـ Promises بطريقة تخلي الكود يبدو وكأنه متزامن (synchronous) وسهل القراءة. async بتخلي الدالة ترجع Promise، وawait بتوقف تنفيذ الدالة لحد ما الـ Promise اللي بتنتظره يرجع نتيجة.

ملاحظة: await يمكن استخدامها فقط داخل دالة معلمة بـ async.

مثال:

async function getDataAsync() {
    console.log('بدأ جلب البيانات...');
    try {
        const response = await fetch('https://api.example.com/data'); // افترض هذا API حقيقي
        const data = await response.json();
        console.log('البيانات المستلمة:', data);
    } catch (error) {
        console.error('حدث خطأ:', error);
    } finally {
        console.log('انتهت دالة جلب البيانات.');
    }
}

getDataAsync();
console.log('الكود يستمر في التنفيذ بعد استدعاء getDataAsync.');

الـ fetch هنا عملية غير متزامنة، لكن باستخدام await، الكود داخل getDataAsync بيبدو وكأنه بيتنفذ سطر بسطر.

خلاصة

المزامنة في JavaScript هي أساس بناء تطبيقات ويب حديثة وسريعة الاستجابة. فهمك لكيفية عمل الـ Event Loop واستخدامك الفعال للـ Callbacks، Promises، وAsync/Await حيخليك تكتب كود أنظف وأكثر كفاءة.