تحليل أداء كود JavaScript: إيجاد نقاط الاختناق عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يُعد تحليل الأداء الخطوة الأولى نحو التحسين

\n

تحسين الكود دون تحليل مسبق للأداء هو بمثابة إطلاق نار في الظلام. غالبًا ما يقضي المطورون ساعات في "تحسين" أجزاء من الكود ليست في الحقيقة نقاط اختناق. يتيح لك تحليل أداء كود JavaScript تحديد الوظائف التي تستهلك معظم وقت المعالج بدقة، وأين يحدث تسرب للذاكرة، وأي العمليات تحظر Event Loop.

\n

في هذه المقالة، سنستعرض الطرق العملية لتحليل الأداء في بيئة Node.js، باستخدام الأدوات المدمجة وأدوات المتصفح. ستتعلم كيفية إيجاد مشاكل الأداء الحقيقية، بدلاً من التخمين.

\n\n

1. أدوات تحليل أداء Node.js

\n

توفر Node.js العديد من الأدوات القوية، ولكن غالبًا ما يتم التقليل من قيمتها. دعنا نستعرض ثلاثة أساليب رئيسية.

\n\n

1.1. ملف تعريف V8 المدمج

\n

أسهل طريقة للحصول على ملف تعريف هي تشغيل السكريبت مع العلم --prof:

\n
node --prof app.js
\n

بعد انتهاء السكريبت، يتم إنشاء ملف isolate-0x...-v8.log. لتحويله إلى نص قابل للقراءة، استخدم:

\n
node --prof-process isolate-0x...-v8.log > profile.txt
\n

مثال على الإخراج (مبسط):

\n
Statistical profiling result from isolate-0x3a00000-v8.log, (1002 ticks, 1 unaccounted, 0 excluded).\n\n [Shared libraries]:\n   ticks  total  nonlib   name\n     10   1.0%          /lib/x86_64-linux-gnu/libc-2.31.so\n\n [JavaScript]:\n   ticks  total  nonlib   name\n    450   44.9%   45.5%  LazyCompile: *processData /home/user/app.js:12:17\n    200   20.0%   20.2%  LazyCompile: *fetchFromDB /home/user/app.js:34:23\n    100   10.0%   10.1%  Builtin: CallFunctionReceiver\n
\n

هنا نرى أن الدالة processData تستهلك ما يقرب من نصف الوقت - وهذا هدف واضح للتحسين.

\n\n

1.2. Chrome DevTools لـ Node.js

\n

للحصول على تحليل بصري أكثر، استخدم Chrome DevTools. قم بتشغيل التطبيق مع العلم --inspect:

\n
node --inspect app.js
\n

افتح في Chrome chrome://inspect واضغط على "Open dedicated DevTools for Node". سترى علامات التبويب Profiler (أو Performance في الإصدارات الأحدث). سجل ملف تعريف، وقم بتنفيذ الإجراء المطلوب في التطبيق، ثم حلل Flame Graph (مخطط اللهب).

\n

يظهر Flame Graph الوظائف التي تستدعي بعضها البعض ومقدار الوقت الذي تستغرقه. "الأعمدة" العريضة هي الوظائف الأكثر استهلاكًا للوقت.

\n\n

1.3. console.time و console.timeEnd

\n

للقياسات السريعة والنقطية، استخدم الزوج console.time / console.timeEnd:

\n
console.time('parseJSON');\nconst data = JSON.parse(largeString);\nconsole.timeEnd('parseJSON'); // parseJSON: 12.345 ms
\n

هذه الطريقة لا تتطلب تشغيل ملف تعريف منفصل وهي مثالية لتصحيح الأخطاء المحلي. لكن تذكر: النتائج تتأثر بحمل CPU الحالي، لذا قم بعدة قياسات.

\n\n

2. مثال عملي: إيجاد نقطة اختناق في خادم ويب

\n

لنتخيل أن لدينا خادم HTTP بسيط على Express، يعالج الطلبات، ويحمل البيانات من ملف، ويقوم بحسابات معقدة. مهمتنا هي إيجاد سبب تباطؤ الاستجابات تحت الحمل.

\n\n

2.1. الكود الأصلي (به مشكلة)

\n
const express = require('express');\nconst fs = require('fs');\nconst app = express();\n\napp.get('/data', (req, res) => {\n    console.time('total');\n    \n    // قراءة الملف بشكل متزامن (عملية حظر)\n    const fileData = fs.readFileSync('./large-file.json', 'utf8');\n    \n    // تحليل JSON\n    const json = JSON.parse(fileData);\n    \n    // تحويل معقد\n    const result = json.map(item => {\n        let sum = 0;\n        for (let i = 0; i < 10000; i++) {\n            sum += Math.sqrt(item.value * i);\n        }\n        return { id: item.id, sum };\n    })                

المدونات

توصيات الكتب