تحليل أداء كود JavaScript: إيجاد نقاط الاختناق
\n\nعندما يبدأ مشروع Node.js الخاص بك في التباطؤ، أول فكرة تتبادر إلى الذهن هي "يجب إعادة كتابة كل شيء بلغة Rust". لكن لا تتعجل! غالباً ما تكمن المشكلة في بضعة أسطر من الكود تعمل بشكل غير فعال. في هذه المقالة، سنشرح كيفية إيجاد هذه "الاختناقات" باستخدام أدوات تحليل أداء بسيطة. ستتعلم كيفية قياس الأداء، وإنشاء flamegraph، وفهم أين تذهب طاقة المعالج (CPU).
\n\nلماذا تحليل أداء الكود؟
\n\nتخيل أن خادمك يعالج 100 طلب في الثانية، بينما تحتاج إلى 500. يمكنك تحسين كل شيء عشوائياً، لكن هذا سيستغرق أسابيع. أو يمكنك إيجاد دالة واحدة تستغرق 80% من الوقت، وإصلاحها في ساعة. تحليل الأداء هو بالضبط ما يوضح أين يضيع الوقت.
\n\nلننظر في السيناريوهات الرئيسية التي يكون فيها تحليل الأداء ضرورياً:
\n- \n
- زمن استجابة عالي لواجهات API \n
- تسرب الذاكرة (memory leaks) \n
- حمل عالي على المعالج (CPU) دون أسباب واضحة \n
- معالجة بطيئة لمصفوفات بيانات كبيرة \n
الأداة 1: محلل Node.js المدمج (--prof)
\n\nأبسط طريقة هي تشغيل Node.js مع العلم --prof. يقوم بجمع إحصائيات التنفيذ وحفظها في ملف isolate-*.log.
لننشئ سكريبت اختبار يحتوي على نقطة اختناق:
\n\n// slow.js\nfunction heavyComputation() {\n let sum = 0;\n for (let i = 0; i < 1e7; i++) {\n sum += Math.sqrt(i) * Math.sin(i);\n }\n return sum;\n}\n\nfunction fastFunction() {\n return 42;\n}\n\nconsole.time('total');\nheavyComputation();\nfastFunction();\nconsole.timeEnd('total');\n\n\nلنشغل تحليل الأداء:
\nnode --prof slow.js\n\nبعد التنفيذ، سيظهر ملف isolate-0x...-v8.log. لقراءته، نستخدم الأداة node --prof-process:
node --prof-process isolate-0x...-v8.log > profile.txt\n\nلنفتح profile.txt وسنرى جدولاً بنسب الوقت:
[Summary]:\n ticks total nonlib name\n 785 78.5% 85.3% JavaScript\n 215 21.5% 14.7% C++\n ...\n[Bottom up (heavy) profile]:\n ticks parent name\n 500 50.0% LazyCompile: *heavyComputation slow.js:2:17\n 100 10.0% Builtin: MathSqrt\n 50 5.0% Builtin: MathSin\n\n\nنرى أن 50% من الوقت يذهب إلى الدالة heavyComputation. الآن نعرف ما يجب تحسينه أولاً.
الأداة 2: Chrome DevTools (المفتش)
\n\nلتحليل أكثر وضوحاً، سنتصل بـ Chrome DevTools. لنشغل Node.js مع العلم --inspect:
node --inspect slow.js\n\nلنفتح Chrome ونذهب إلى العنوان chrome://inspect. نضغط على "Open dedicated DevTools for Node". علامة التبويب "Profiler" ← "Start" ← شغّل السكريبت ← "Stop".
سترى flamegraph - رسم بياني حيث عرض الكتلة يظهر وقت التنفيذ. كلما كانت الكتلة أعرض، كانت الدالة "أسخن". ستكون heavyComputation لدينا مستطيلاً ضخماً.
نصيحة: استخدم فلتر "Focus selected" على الدالة لرؤية استدعاءاتها الداخلية. على سبيل المثال، ستلاحظ أن Math.sqrt يتم استدعاؤه 10 ملايين مرة - ربما يجب حساب الجذور مسبقاً.
الأداة 3: perf_hooks - قياسات دقيقة داخل الكود
\n\nأحياناً تحتاج لقياس جزء معين من الكود دون تشغيل أدوات خارجية. لهذا نستخدم الوحدة المدمجة perf_hooks.
مثال لقياس وقت تنفيذ دالة:
\n\nconst { performance } = require('perf_hooks');\n\nfunction processData(items) {\n let result = [];\n for (let item of items) {\n // محاكاة معالجة معقدة\n for (let j = 0; j < 1000; j++) {\n result.push(item * j);\n }\n