محرّك V8
Node.js مبني على محرّك V8 من جوجل — نفس المحرّك الذي يشغّل JavaScript في متصفّح Chrome. V8 يترجم JavaScript إلى لغة الآلة مباشرة، ما يجعله سريعًا جدًّا.
الفكرة العبقرية: أخذوا محرّك المتصفّح وشغّلوه على الخادم، فأصبح بإمكاننا كتابة الخلفية (Backend) بنفس لغة الواجهة.
البنية أحادية الخيط (Single-Threaded)
على عكس الخوادم التقليدية التي تفتح خيطًا (Thread) لكل طلب، يعمل Node على خيط واحد يخدم آلاف الطلبات. السرّ في عدم الحجب (Non-Blocking).
نموذج عدم الحجب (Non-Blocking I/O)
عندما يطلب الكود عملية بطيئة (قراءة ملف، استعلام قاعدة بيانات)، لا ينتظرها Node — بل يسجّلها ويكمل تنفيذ بقية الكود، ثم يعالج النتيجة عند جاهزيتها:
const fs = require("fs");
console.log("1 - قبل القراءة");
fs.readFile("file.txt", "utf-8", (err, data) => {
console.log("3 - وصلت البيانات");
});
console.log("2 - بعد استدعاء القراءة");
// الترتيب: 1 ثم 2 ثم 3
لاحظ أن 2 طُبع قبل 3 رغم أن القراءة استُدعيت أولًا — لأن Node لم يحجب
التنفيذ بانتظار الملف.
حلقة الأحداث (Event Loop)
هي قلب Node — حلقة لا نهائية تراقب المهام المنتهية وتنفّذ ردودها (callbacks). مبسّطًا:
- ينفّذ الكود المتزامن (synchronous) أولًا.
- يرسل العمليات البطيئة للنظام لتعمل في الخلفية.
- عند انتهائها، يضع ردودها في طابور.
- حلقة الأحداث تسحب من الطابور وتنفّذ الردود.
console.log("بداية");
setTimeout(() => console.log("مؤقّت"), 0);
Promise.resolve().then(() => console.log("وعد"));
console.log("نهاية");
// الترتيب: بداية، نهاية، وعد، مؤقّت
الوعود (microtasks) لها أولوية على المؤقّتات (macrotasks) — لذا "وعد" قبل "مؤقّت".
لماذا هذا مهم؟
- Node ممتاز للتطبيقات كثيرة الإدخال/الإخراج (APIs، الدردشة، البث).
- لكن العمليات الحسابية الثقيلة تحجب الخيط الوحيد — لها حلول لاحقة (Worker Threads).
أخطاء شائعة
- توقّع تنفيذ الكود غير المتزامن بالترتيب الذي كُتب به.
- تشغيل حسابات ثقيلة تحجب حلقة الأحداث فيتجمّد الخادم لكل المستخدمين.
🎯 التالي: سطر الأوامر وكائن process.