شرح حلقة الأحداث (Event Loop) في Node.js

يستخدم Node.js خيطاً واحداً (single thread). قد تتساءل كيف يمكنه التعامل مع آلاف الطلبات في وقت واحد.

السر يكمن في حلقة الأحداث (Event Loop).

بدلاً من انتظار انتهاء المهمة، يقوم Node.js بإرسال المهام التي تستغرق وقتاً طويلاً إلى نظام التشغيل، ويستمر في الانتقال إلى المهمة التالية. هذا ما يجعل تطبيقاتك سريعة وسريعة الاستجابة.

العمليات المعيقة (Blocking) مقابل العمليات غير المعيقة (Non-blocking)

إذا استخدمت دوالاً متزامنة (sync) مثل readFileSync ، سيتوقف الخادم؛ حيث سينتظر انتهاء قراءة الملف، ولن يحصل أي مستخدم آخر على استجابة. هذا يدمر أداء تطبيقك.

أما إذا استخدمت fs.readFile ، فسيستمر الخادم في العمل، حيث سيتعامل مع الطلبات الأخرى بينما يتم قراءة الملف في الخلفية.

كيف تعمل حلقة الأحداث (Event Loop)

تمر الحلقة بعدة مراحل:

• المؤقتات (Timers): تتعامل مع setTimeout و setInterval. • استدعاءات الانتظار (Pending Callbacks): تتعامل مع أخطاء مستوى النظام. • الاستطلاع (Poll): يستقبل الاتصالات الجديدة ويتعامل مع عمليات الإدخال والإخراج (I/O) مثل استعلامات قواعد البيانات. • التحقق (Check): تتعامل مع setImmediate. • استدعاءات الإغلاق (Close Callbacks): تتعامل مع إغلاق المقابس (socket closures).

ترتيب الأولويات

ليست كل المهام متساوية، حيث يستخدم Node.js طابورين:

  1. طابور المهام الدقيقة (Microtask Queue): يحتوي على الوعود (Promises).
  2. طابور الاستدعاءات (Callback Queue): يحتوي على setTimeout وعمليات الإدخال والإخراج (I/O).

يعمل طابور المهام الدقيقة (Microtask Queue) دائماً أولاً. فإذا كان لديك Promise و setTimeout ، فسيتم تنفيذ الـ Promise قبل المؤقت.

مكدس الاستدعاءات (Call Stack) والطوابير

يتتبع مكدس الاستدعاءات (Call Stack) الكود الذي يتم تنفيذه حالياً. وعندما تنتهي مهمة ما، يدخل الاستدعاء الخاص بها (callback) في طابور. وتنتظر حلقة الأحداث (Event Loop) حتى يفرغ مكدس الاستدعاءات قبل أن تسحب المهام من الطابور.

تجنب هذه الأخطاء:

• لا تستخدم الحلقات اللانهائية (infinite loops)، لأن ذلك سيؤدي إلى تجميد تطبيقك بالكامل. • لا تستخدم طرق التعامل مع الملفات المتزامنة (synchronous) في بيئة الإنتاج (production). • لا تقم بتشغيل العمليات الحسابية الثقيلة أو معالجة الفيديو على الخيط الرئيسي (main thread).

للمهام الثقيلة، استخدم خيوط العمل (Worker Threads) أو المهام الخلفية (background jobs).

ملخص

Node.js سريع لأنه لا ينتظر؛ فهو يفوض مهام الإدخال والإخراج (I/O) ويستخدم حلقة الأحداث (Event Loop) لإدارة النتائج. تتيح هذه البنية لخيط واحد خدمة العديد من المستخدمين.

ما هو الجزء الأصعب بالنسبة لك في تعلم حلقة الأحداث (Event Loop)؟ أخبرني في التعليقات.

المصدر: https://dev.to/synfinity-dynamics-pvt-ltd/nodejs-event-loop-explained-how-nodejs-handles-thousands-of-concurrent-requests-1heo