عندما يخرج JavaScript من المتصفح
\n\nمعظم المطورين اعتادوا على اعتبار JavaScript لغة "لإحياء" صفحات الويب. لكن ماذا لو أخبرتك أنه يمكنك كتابة سكربتات للتحكم في نظام التشغيل باستخدام JavaScript، والتعامل مع نظام الملفات على مستوى منخفض، وحتى إنشاء خدمات شبكية دائمة؟ يبدو هذا كخيال علمي؟ لكنه حقيقة. بفضل بيئات التشغيل مثل Node.js و Deno، أصبح JavaScript للبرمجة النظامية أداة فعالة وليست مجرد فكرة. في هذا المقال، سنستعرض أمثلة عملية ونرى كيف يتعامل JS مع مهام كانت حكراً على C أو Rust أو Python.
\n\nلماذا JavaScript؟ المزايا والتحديات
\n\nقبل الغوص في الكود، دعنا نقيم الموقف بموضوعية. البرمجة النظامية باستخدام Node.js لها نقاط قوة وضعف.
\n\nالمزايا:
\n- \n
- توحيد التقنيات — إذا كنت مطور واجهات أمامية، فلن تحتاج لتعلم لغة جديدة لكتابة أدوات سطر الأوامر. \n
- مجتمع ضخم — npm يوفر آلاف الحزم للتعامل مع النظام. \n
- غير متزامن بشكل افتراضي — الإدخال/الإخراج غير المحظور مثالي للعمل مع الشبكة والملفات. \n
- نموذج أولي سريع — يمكنك كتابة سكربت JS في دقائق. \n
التحديات:
\n- \n
- الأداء — JS أبطأ من C أو Rust في المهام الحسابية. \n
- وصول محدود للعتاد — لا يوجد تعامل مباشر مع الذاكرة أو منافذ الإدخال/الإخراج (رغم وجود حلول بديلة). \n
- استهلاك الذاكرة — محرك V8 ليس الأخف وزناً. \n
ومع ذلك، فإن 80% من مهام إدارة النظام والأتمتة تناسب JavaScript للبرمجة النظامية بشكل ممتاز. دعنا ننتقل إلى التطبيق العملي.
\n\nالتعامل مع نظام الملفات: وحدة fs
\n\nلنبدأ بالأساسيات — التعامل مع الملفات باستخدام JavaScript. توفر وحدة fs في Node.js طرقاً متزامنة وغير متزامنة للتفاعل مع نظام الملفات.
قراءة وكتابة الملفات (النسخة غير المتزامنة)
\n\nconst fs = require('fs').promises;\nconst path = require('path');\n\nasync function processLogFile(filePath) {\n try {\n // قراءة الملف\n const data = await fs.readFile(filePath, 'utf-8');\n const lines = data.split('\\n');\n \n // تصفية الأسطر التي تحتوي على أخطاء فقط\n const errors = lines.filter(line => line.includes('ERROR'));\n \n // كتابة النتيجة\n const outputPath = path.join(__dirname, 'errors.log');\n await fs.writeFile(outputPath, errors.join('\\n'), 'utf-8');\n \n console.log(`تمت معالجة ${lines.length} سطر، وُجد ${errors.length} خطأ`);\n } catch (err) {\n console.error('خطأ في التعامل مع الملف:', err);\n }\n}\n\nprocessLogFile('/var/log/application.log');\n\nهذا السكربت هو مثال نموذجي لـ سكربت نظامي باستخدام JavaScript. يقرأ ملف سجلات كبير، يصفي البيانات، ويكتب النتيجة. النسخة غير المتزامنة لا تعطل event loop، وهو أمر حاسم لتطبيقات الخادم.
\n\nمراقبة التغييرات في نظام الملفات
\n\nمن الإمكانيات القوية مراقبة الملفات في الوقت الفعلي:
\n\nconst fs = require('fs');\n\nconst watcher = fs.watch('/etc/config', { recursive: true });\n\nwatcher.on('change', (eventType, filename) => {\n console.log(`تغيير في الملف: ${filename} (${eventType})`);\n \n // إعادة تحميل الإعدادات تلقائياً\n if (filename.endsWith('.conf')) {\n const config = fs.readFileSync(`/etc/config/${filename}`, 'utf-8');\n console.log('تم تحميل الإعدادات الجديدة');\n }\n});\n\nconsole.log('مراقبة الإعدادات قيد التشغيل');\n\n\nهذا النوع من السكربتات مفيد جداً في إدارة النظام باستخدام JavaScript، خاصة عند الحاجة لإعادة تحميل الإعدادات تلقائياً دون إعادة تشغيل الخدمات.