توصيف كود TypeScript: العثور على نقاط الاختناق عمليًا
عندما يبدأ مشروع TypeScript الخاص بك في التباطؤ ويشتكي المستخدمون من التأخير، يحين وقت التوصيف. التوصيف ليس مجرد "معرفة ما هو بطيء"، بل هو نهج منهجي لتحديد نقاط الاختناق في أداء الكود. في هذه المقالة، سنستعرض الطرق العملية لتوصيف كود TypeScript مع أمثلة حقيقية وأدوات.
لماذا توصيف كود TypeScript؟
يتم تجميع TypeScript إلى JavaScript، وجميع مشاكل الأداء المتعلقة بـ JS تنتقل إلى TS. ومع ذلك، يضيف TypeScript فروقه الدقيقة: الأنماط، الديكورات، الأدوية العامة قد تخلق تكاليف إضافية غير متوقعة. يساعد التوصيف في الإجابة على الأسئلة:
- أي دالة تستغرق وقتًا أطول في التنفيذ؟
- أين يحدث تسرب الذاكرة؟
- لماذا تتباطأ الرسوم المتحركة عند 60 إطارًا في الثانية؟
- أي خوارزمية تحتاج إلى تحسين؟
أدوات توصيف TypeScript
Chrome DevTools (لكود المتصفح)
الأداة الأقوى للواجهة الأمامية. افتح علامة التبويب Performance، اضغط على Record، نفذ الإجراء وأوقف التسجيل. سترى flamegraph - تصورًا لاستدعاءات الدوال وأوقات تنفيذها.
// مثال على كود بطيء للتوصيفfunction heavyCalculation(iterations: number): number { let result = 0; for (let i = 0; i < iterations; i++) { result += Math.sqrt(i) * Math.sin(i); } return result;}
// قم بتشغيله في وحدة تحكم المتصفح، ثم قم بالتوصيفheavyCalculation(1000000);Node.js — الموصف المدمج
لكود الخادم، استخدم العلم --inspect و Chrome DevTools، أو العلم المدمج --prof لتوليد السجلات.
// server.tsimport express from 'express';
const app = express();
app.get('/heavy', (req, res) => { const data = processData(10000); res.json({ result: data });});
function processData(size: number): number[] { const arr: number[] = []; for (let i = 0; i < size; i++) { arr.push(i * Math.random()); } return arr.sort((a, b) => a - b);}
app.listen(3000);// التشغيل: node --prof dist/server.jsBenchmark.js للقياسات الدقيقة
عند الحاجة لمقارنة تطبيقين، استخدم مكتبة benchmark.
import Benchmark from 'benchmark';
const suite = new Benchmark.Suite();
// الخيار البطيءfunction slowSearch(arr: number[], target: number): boolean { for (let i = 0; i < arr.length; i++) { if (arr[i] === target) return true; } return false;}
// الخيار السريع باستخدام Setfunction fastSearch(arr: number[], target: number): boolean { const set = new Set(arr); return set.has(target);}
const testArray = Array.from({ length: 10000 }, (_, i) => i);
suite .add('slowSearch', () => slowSearch(testArray, 9999)) .add('fastSearch', () => fastSearch(testArray, 9999)) .on('cycle', (event: any) => console.log(String(event.target))) .on('complete', function(this: any) { console.log('Fastest is ' + this.filter('fastest').map('name')); }) .run({ async: true });أمثلة عملية للعثور على نقاط الاختناق
مثال 1: تسرب الذاكرة عبر الإغلاقات
مشكلة نموذجية في تطبيقات React - الإغلاقات التي تحتفظ بمراجع لكائنات كبيرة.
// الكود المشكلfunction createHeavyComponent() { const hugeData = new Array(1000000).fill('data'); return { getData: () => hugeData, // الإغلاق يحتفظ بـ hugeData updateData: (newData: string) => { // تحوير، لكن المرجع يبقى hugeData.push(newData); } };}
const component = createHeavyComponent();// hugeData لن يتم جمعه بواسطة GC طالما أن component موجود<