- يُعد شحن إصدار React الصحيح وتحسين أداة التجميع الخاصة بك (إصدارات الإنتاج والتحليل) هو الأساس لأي عمل جاد لتحسين الأداء.
- يكشف التحليل باستخدام أدوات مطوري React ومسارات أداء المتصفح عن عمليات العرض غير الضرورية والتأثيرات البطيئة واختناقات الخادم التي يمكنك استهدافها بعد ذلك.
- تعمل تقنيات التخزين المؤقت وعدم قابلية التغيير والمحاكاة الافتراضية معًا لتقليل تكرار العرض، وتقليص العمل لكل عملية عرض، والحفاظ على سلاسة واجهات المستخدم الكبيرة.
- يضمن تقسيم الكود، وSSR، وWeb Workers، والمراقبة المستمرة سرعة التحميل الأولي، والتفاعلات السريعة، والأداء المستدام على نطاق واسع.

قد يبدو React سريعًا للغاية عند استخدامه لأول مرة، ولكن مع نمو تطبيقك، يصبح من السهل بشكل مدهش تراكم تراجعات طفيفة في الأداء. مما يحول واجهات المستخدم السلسة إلى تطبيقات بطيئة تستهلك طاقة البطارية بشكل مفرط. القوائم الطويلة، والمكونات الثقيلة، وهياكل الحالة المعقدة، وإصدارات التصحيح في بيئة الإنتاج، كلها عوامل تتراكم حتى يبدأ المستخدمون في التخلي عن صفحاتك.
والخبر السار هو أن React يأتي مزودًا بمجموعة أدوات غنية لقياس وفهم وتحسين أداء العرضوالنظام البيئي المحيط (أدوات تجميع البيانات، وأدوات تحليل الأداء، ومكتبات النوافذ، وWeb Workers، وأطر عمل SSR) يوفر لك كل ما تحتاجه للحفاظ على سرعة استجابة واجهة المستخدم حتى مع زيادة حجم التطبيق. في هذا الدليل، سنستعرض هذه الأدوات بالتفصيل، ونوضح كيفية تكاملها، ونسلط الضوء على بعض الحيل الأقل وضوحًا التي غالبًا ما تتجاهلها الفرق، ولكنها تستحق التجربة بالتأكيد.
استخدم إصدار React المناسب: التطوير، والإنتاج، والتحليل.
أول فحص لأداء أي تطبيق React هو التأكد من أنك تقوم بنشر نسخة الإنتاج، وليس نسخة التطوير.تتضمن نسخة التطوير الكثير من التحذيرات الودية والفحوصات الإضافية وأدوات المساعدة في تصحيح الأخطاء التي تعتبر رائعة أثناء البرمجة ولكنها أبطأ وأكبر حجمًا بشكل ملحوظ في بيئة الإنتاج.
يمكنك التأكد من الإصدار الذي تستخدمه باستخدام إضافة React Developer Tools للمتصفحعند فتح موقع يستخدم React، يظهر رمز الإضافة بخلفية داكنة في بيئة الإنتاج وخلفية حمراء في بيئة التطوير. إذا ظهر اللون الأحمر على موقعك المباشر، فهذا يعني أن إعدادات مُجمِّع الحزم لديك تُسرِّب إصدارًا خاطئًا.
بالنسبة للمشاريع التي تم إنشاؤها باستخدام Create React App، فإن إنشاء حزمة إنتاج محسّنة أمر بسيط مثل تشغيل برنامج البناء الخاص بك.، والذي يُخرج حزمة مُصغّرة إلى build/ الدليل. أثناء التطوير المحلي، يجب عليك الالتزام بـ npm start (أو ما يعادلها) وتشغيل إصدار الإنتاج فقط للنشر أو للحصول على معايير أداء واقعية.
إذا كنت تعتمد على إصدارات UMD أحادية الملف من React و React DOM (على سبيل المثال في بيئة غير مجمعة)تأكد من تضمين الملفات التي تنتهي بـ .production.min.jsأي ملف غير مضغوط أو غير مخصص للإنتاج مخصص للتطوير فقط وسيؤدي إلى تحميل المستخدمين بأعباء تصحيح الأخطاء غير الضرورية.
أدوات تجميع الملفات: Browserify و Rollup و Brunch و webpack
تتطلب أدوات التجميع المختلفة تعديلات مختلفة لتمكين تحسينات الإنتاج الخاصة بـ React بشكل كامل.، لكنها جميعها تتبع نفس الفكرة الأساسية: ضبط البيئة على وضع الإنتاج، وإزالة الفروع المخصصة للتطوير فقط، وتصغير ملف جافا سكريبت الناتج.
مع برنامج Brunch، يُنصح بتثبيت إضافة لتقليص حجم الملفات مثل: terser-brunchثم قم بتشغيل عملية البناء باستخدام علامة الإنتاج (على سبيل المثال باستخدام -p). يضمن هذا التكوين إزالة التحذيرات أثناء التطوير وضغط الحزمة النهائية بشكل مكثف.
بالنسبة لـ Browserify، عادةً ما تقوم بربط بعض التحويلات بترتيب محدد.: قم بالتقديم أولاً envify على مستوى العالم لحقن NODE_ENV="production"، ثم قم بالتقديم uglifyify على مستوى العالم لمحو عمليات استيراد التطوير ومسارات التعليمات البرمجية، وأخيراً تمرير الحزمة من خلال terser لأغراض التشويه والضغط. الترتيب مهم هنا لأن كل خطوة تُهيئ الكود للتحويل التالي.
عند استخدام Rollup، تقوم بتوصيل ثلاثة مكونات إضافية للوصول إلى إصدار إنتاجي بسيط.: replace يُهيئ البيئة للإنتاج، commonjs يسمح بتجميع وحدات CommonJS، و terser يقوم هذا البرنامج بعملية التصغير والتعديل النهائية. ينتج عن هذه العملية حزمة صغيرة جاهزة للإنتاج بدون الأدوات المساعدة المخصصة للمطورين فقط.
مع Webpack 4 والإصدارات الأحدث، يؤدي تفعيل وضع الإنتاج تلقائيًا إلى تنشيط العديد من التحسينات، بما في ذلك تصغير الملفات.. ضبط mode: 'production' تُشغّل الأسلاك في Terser من الداخل وتُمكّن سلوك الإنتاج في React طالما NODE_ENV عادةً لا تحتاج إلى إضافة أداة تصغير منفصلة إلا إذا كانت لديك متطلبات محددة للغاية.
تحليل إصدارات React
بالإضافة إلى إصدارات التطوير والإنتاج العادية، يوفر React أيضًا إصدارًا خاصًا لتحليل الأداء يركز على تحليل الأداء. يقوم هذا الإصدار بتجهيز React داخليًا بحيث يمكن لأدوات مثل DevTools Profiler جمع معلومات توقيت مفصلة للغاية.
لاستخدام إصدار التنميط في بيئة المتصفح، عليك الاستيراد react-dom/profiling بدلا من react-dom/client وعادةً ما يتم تكوين اسم مستعار للمُجمِّع لتجنب الحاجة إلى تعديل كل عملية استيراد يدويًا. بعض الأطر البرمجية توفر بالفعل خيارًا أو وضعًا لتفعيل هذا السلوك تلقائيًا.
اعتمدت الإصدارات السابقة من React (قبل الإصدار 17) على واجهة برمجة تطبيقات توقيت المستخدم القياسية لإصدار علامات ومقاييس مرئية في لوحة الأداء بالمتصفح. يجمع React الحديث هذه الإمكانيات مع علامة تبويب Profiler المخصصة في أدوات مطوري React، مما يتيح لك التعمق في المكونات مباشرةً.
فهم وقياس أداء React
لا يمكنك إصلاح ما لا تقيسه، لذا يجب أن يبدأ تحسين الأداء في React دائمًا بتحليل الأداء.وهذا يعني استخدام أدوات المتصفح وأدوات تحليل الأداء الخاصة بـ React لمعرفة أين يتم قضاء الوقت فعليًا وأي المكونات يتم إعادة عرضها أكثر مما ينبغي.
تُعد لوحة أداء أدوات مطوري Chrome هي الأساس لفهم ما يفعله المتصفحيتم عرض تنفيذ جافا سكريبت، وطلبات الشبكة، والتخطيط، والرسومات، وتأخيرات حلقة الأحداث، والتتبعات المخصصة جميعها على خط زمني موحد. يتكامل React مع هذا العرض من خلال مسارات متخصصة تكشف عن الأنشطة الخاصة بالإطار.
تُتيح تقنية React الحديثة إمكانية تتبع الجدولة والمكونات والخادم، والتي تتوافق مع عمليات التتبع العادية للمتصفح.. يمنحك هذا عرضًا متزامنًا لتحديثات الشبكة وجافا سكريبت ورياكت، وهو أمر مفيد للغاية عندما تتعقب الأعطال أو التوقفات الغريبة التي تظهر فقط تحت الحمل.
يقوم المجدول بتتبع المراحل وعرضها
المُجدول هو تجريد داخلي لـ React يقوم بتنسيق العمل وفقًا لأولويات مختلفةفي سجلات الأداء، سترى مسارات فرعية منفصلة للعمليات التي تعيق عمل النظام (غالبًا ما تكون تحديثات متزامنة يقوم بها المستخدم)، وعمليات الانتقال (تحديثات واجهة المستخدم في الخلفية التي يتم تشغيلها بواسطة startTransition)، المهام المتعلقة بالتشويق والعمل الخامل الذي يتم تنفيذه عندما لا يكون هناك شيء أكثر إلحاحًا معلقًا.
تمر كل عملية عرض بعدة مراحل متميزة يمكنك معاينتها على الخط الزمنيمرحلة التحديث (ما الذي أدى إلى عملية العرض)، ومرحلة العرض (حيث يستدعي React مكوناتك ويبني الشجرة التالية)، ومرحلة الالتزام (حيث يتم تغيير DOM وتطبيق تأثيرات التخطيط مثل useLayoutEffect (تشغيل) ومرحلة التأثيرات المتبقية (حيث التأثيرات السلبية مثل useEffect (عادةً ما يستغرق الأمر وقتًا أطول بعد الطلاء).
تُعدّ التحديثات المتتالية - تغييرات الحالة المجدولة أثناء عملية العرض - مصدرًا كلاسيكيًا لمشاكل الأداء الخفية.في مرحلة التطوير، يمكن لـ React الإشارة إلى هذه الأمور في الجدول الزمني، بل ويمكنها أيضًا إظهار المكون والطريقة التي قامت بجدولة التحديث الإضافي، مما يساعدك على تجنب حلقات العرض غير المقصودة أو العمل المتكرر.
مسار المكونات: مخططات اللهب للرسومات والتأثيرات
يُظهر مسار المكونات المدة التي يستغرقها عرض كل مكون (ومكوناته الفرعية). باستخدام مخطط اللهب. كلما اتسعت الكتلة على المخطط، زاد الوقت الذي استهلكته شجرة المكونات الفرعية في عملية العرض تلك.
يعرض React أيضًا مدة التأثيرات كرسم بياني منفصل. مع نظام ألوان يعكس المرحلة المقابلة في مسار الجدولة، بحيث يمكنك التمييز بين وقت العرض ووقت التأثير بنظرة سريعة.
تظهر أحداث إضافية مثل عمليات التثبيت والفك وإعادة الاتصال والانقطاع كتعليقات توضيحية على هذه المخططات اللهبية.على سبيل المثال، سيتم وضع علامة على تركيب جزء جديد من الشجرة أو هدم جزء منها، وبعض الميزات مثل <Activity> تحصل المكونات على علامات إعادة الاتصال/الفصل الخاصة بها.
في وضع التطوير، يُظهر النقر على عنصر عرض في مسار المكونات الخصائص التي تم تغييرها، وهو أمر مفيد للغاية عندما تحاول تتبع عمليات العرض غير الضرورية أو الخصائص التي تستمر في تغيير المراجع دون تغيير القيمة فعليًا.
يتتبع الخادم: الطلبات ومكونات الخادم
إذا كنت تستخدم مكونات خادم React، فيمكن لأدوات قياس الأداء أيضًا إظهار سلوك جانب الخادميقوم مسار "طلبات الخادم" بتجميع الوعود التي تُغذي في النهاية مكونات الخادم بالبيانات، بما في ذلك استدعاءات لـ fetch أو عمليات نظام الملفات غير المتزامنة.
يحاول React تجميع الوعود التي تم إنشاؤها في أدوات مساعدة خارجية في نطاق واحد لذا سترى عملية منطقية واحدة مثل getUser بدلاً من عشرات المستويات المنخفضة fetch المكالمات. يؤدي النقر على نطاق إلى إظهار مكان إنشائه، وعند توفره، القيمة التي تم حلها أو سبب الرفض.
يعرض مسار مكونات الخادم المنفصل المدة التي تستغرقها أشجار مكونات الخادم والوعود التي تنتظرهاكما يمكن عرضها في شكل مخطط اللهب. عندما يستطيع React عرض مكونات الخادم بشكل متزامن، فإنه ينشئ مسارًا رئيسيًا ومسارات متوازية إضافية؛ إذا تجاوز التزامن عددًا معينًا، يتم تجميع العمل الإضافي للحفاظ على سهولة قراءة العرض.
تقليل عمليات العرض غير الضرورية: React.memo، وuseMemo، وuseCallback، وPureComponent
تُعد إعادة العرض غير الضرورية أحد أكبر وأكثر أسباب استنزاف الأداء شيوعًا في تطبيقات React.. في كل مرة يتم فيها تحديث مكون رئيسي، يتم إعادة عرض مكوناته الفرعية بشكل افتراضي، حتى لو كانت مدخلاتها (الخصائص) متطابقة ولن يتغير DOM الناتج فعليًا.
يوفر React العديد من الأدوات لتقليل هذا العمل الضائع: React.memo بالنسبة للمكونات الوظيفية، React.PureComponent بالنسبة لمكونات الفئة، و useMemo/useCallback خطافات لتثبيت القيم التي يتم تمريرها كخصائصهذه الحلول لا تحل جميع مشاكل الأداء بشكل سحري، ولكن استخدامها بشكل مدروس يمكن أن يحدث فرقًا كبيرًا.
React.memo يغلّف مكونًا وظيفيًا ويتخطى إعادة عرضه عندما تكون خصائصه متطابقة تقريبًا مع الخصائص السابقة.. يكون هذا الأمر ذا قيمة كبيرة عندما يتم عرض مكون ما بشكل متكرر بنفس الخصائص، أو يحتوي على منطق عرض ثقيل، أو لديك دليل من محلل الأداء على أنه يمثل عنق زجاجة.
عند تخزين بيانات أحد المكونات مؤقتًا، يجب عليك أيضًا التأكد من أن خصائصه لا تغير هويتها دون داعٍ.. سيؤدي إنشاء كائن جديد أو دالة مضمنة داخل JSX الأصل في كل عملية عرض إلى إبطال المقارنة السطحية وإجبار العنصر الفرعي على إعادة العرض، حتى لو كانت البيانات المنطقية هي نفسها.
هذا هو المكان useMemo و useCallback ادخل: useMemo يعمل على تثبيت قيم الكائنات أو المصفوفات المشتقة من حالات أخرى بحيث لا تتغير إلا عند تغير تبعياتها، useCallback يوفر مراجع وظائف مستقرة لعمليات الاستدعاء التي يتم تمريرها إلى العناصر الفرعية المخزنة مؤقتًا.
مكونات الفئة: shouldComponentUpdate و React.PureComponent
في جوهرها، تتلخص معظم تحسينات عرض React في التحكم فيما إذا كان shouldComponentUpdate تُرجع القيمة صحيحة أو خاطئة. يقوم التنفيذ الافتراضي دائمًا بإرجاع القيمة true، مما يعني أن أي تغيير في الخاصية أو الحالة يؤدي إلى عملية عرض ومطابقة لهذا المكون وشجرة فرعية منه.
عن طريق التجاوز shouldComponentUpdateيمكنك اختصار العمل على الفروع الفرعية التي لا تحتاج إلى تحديث.إذا قمت بإرجاع القيمة false، فلن يقوم React باستدعاء render() بالنسبة لهذا المكون أو أي من مكوناته الفرعية، ولن يقوم حتى بمقارنة عقد DOM الافتراضية الجديدة والقديمة لهذا الجزء من الشجرة.
لنفترض شجرة مكونات صغيرة حيث تُرجع بعض العقد قيمة خاطئة من shouldComponentUpdateيمكن لـ React تخطي عملية التصفح في تلك الفروع تمامًا، بينما ستتم معالجة العقد الأخرى التي تُرجع فيها الدالة القيمة "صحيح" بشكل كامل. في النهاية، ستؤدي العقد التي تغيرت مخرجاتها المعروضة فعليًا فقط إلى تغييرات في DOM.
لأن الكتابة مخصصة shouldComponentUpdate المنطق متكرر، وشحنات React React.PureComponentوهذا يُجري مقارنة سطحية بين الخصائص والحالة الحالية والسابقة. إذا لم يطرأ أي تغيير سطحي، يمكن لـ React تخطي إعادة عرض مكون الفئة بأمان.
عدم قابلية التغيير وأسباب فشل المقارنة السطحية
تفترض المقارنة السطحية أنه إذا تغيرت قيمة ما، فسيتغير مرجعها - وهو افتراض ينهار بمجرد تعديل المصفوفات أو الكائنات الموجودة في مكانها.. هذا مصدر كلاسيكي للأخطاء عند الجمع بين التحسينات القائمة على عدم قابلية التغيير وهياكل البيانات القابلة للتغيير.
تخيل ListOfWords المكون الذي يستقبل words مصفوفة، ثم يتم فصلها بفواصل.، مقترنًا بأحد الوالدين WordAdder المكون الذي يدفع كلمة جديدة إلى نفس المصفوفة. إذا ListOfWords يمتد PureComponent، ستلاحظ المقارنة السطحية نفس مرجع المصفوفة وتفترض عدم حدوث أي تغيير، لذلك لن يتم تحديث واجهة المستخدم.
يكمن الحل في تجنب تعديل الخصائص أو الحالة بشكل مباشر، وبدلاً من ذلك إنشاء مصفوفات أو كائنات جديدة عند تغيير البيانات.. بدلا من words.push(newWord)، ستستخدم words.concat(newWord) أو صيغة الانتشار [...words, newWord]، مما يؤدي إلى إنشاء مرجع جديد للمصفوفة وتفعيل التحديثات الصحيحة.
وينطبق المبدأ نفسه على الأشياءبدلاً من إعادة التعيين colormap.right = 'blue' بالنسبة لكائن موجود، يمكنك إرجاع كائن جديد باستخدام Object.assign({}, colormap, { right: 'blue' }) أو صيغة نشر الكائن { ...colormap, right: 'blue' }وهذا يضمن أن المقارنة السطحية ترى مرجعًا جديدًا وتتعرف على التغيير.
عندما تصبح البيانات متداخلة بشكل عميق، فإن الحفاظ على عدم قابليتها للتغيير يدويًا قد يصبح أمرًا صعبًا.تتيح لك مكتبات مثل Immer أو immutability-helper كتابة كود يبدو إجرائيًا وقابلًا للتغيير، بينما تُنتج داخليًا هياكل جديدة غير قابلة للتغيير، وهو ما يتوافق بشكل جيد مع PureComponent و React.memo.
تحويل القوائم الطويلة وواجهات المستخدم الثقيلة إلى صيغة افتراضية
يُعدّ عرض مئات أو آلاف من عناصر DOM دفعة واحدة أحد أسرع الطرق لتدهور أداء Reactخاصةً على الأجهزة منخفضة المواصفات أو عند دمجها مع تصميمات وصور معقدة. حتى مع وجود عملية توفيق فعّالة، فإن مجرد وجود هذا العدد الكبير من العُقد في الذاكرة وعلى الشاشة يُعد مكلفًا.
تعالج تقنية عرض النوافذ، أو ما يُعرف بظاهرية القوائم، هذه المشكلة من خلال عرض الجزء المرئي فقط من القائمة في نافذة العرض.. أثناء قيام المستخدم بالتمرير، يقوم React بتحميل العناصر الجديدة التي تدخل العرض وإلغاء تحميل تلك التي يتم تمريرها للخارج، مما يحافظ على عدد الصفوف المعروضة ثابتًا تقريبًا.
المكتبات الشائعة مثل react-window و react-virtualized توفير مكونات قابلة لإعادة الاستخدام للقوائم والشبكات والجداول التي تُطبّق استراتيجيات افتراضية فعّالة. فهي تتولى العمليات الحسابية لتحديد العناصر التي يجب عرضها، وتحديد أحجام الحاويات، وتحريكها، وحتى سلوك التحميل اللانهائي.
يتضمن إعداد المحاكاة الافتراضية عادةً ثلاثة أجزاءاختيار المكون المناسب (على سبيل المثال، FixedSizeList للصفوف المتساوية أو VariableSizeList (للارتفاعات الديناميكية)، مما يمنح الحاوية ارتفاعًا ثابتًا مع overflow: scrollوعرض مكون العنصر الذي تطلبه المكتبة فقط، والذي يتم تخزينه عادةً باستخدام React.memo لتجنب عمليات إعادة العرض غير الضرورية.
عند تطبيقها بشكل جيد، تحافظ تقنية المحاكاة الافتراضية على سلاسة أداء التمرير وانخفاض استهلاك الذاكرة حتى مع مجموعات البيانات الضخمة.. استخدمت تطبيقات العالم الحقيقي هذه التقنية لتصفح مجموعات ضخمة بكفاءة - مراجعات الموسيقى، وكتالوجات التجارة الإلكترونية، وصناديق البريد الوارد - دون أن تتوقف واجهة المستخدم عن العمل.
تتطلب إمكانية الوصول بعض الاهتمام الإضافي مع القوائم الافتراضيةيجب التأكد من أن التنقل باستخدام لوحة المفاتيح يعمل، وأن التركيز يتم إدارته بشكل صحيح عند تحميل العناصر وإزالتها، وأن قارئات الشاشة لديها سياق كافٍ من خلال سمات ARIA لفهم الجزء المرئي حاليًا من القائمة.
إدارة الحالة، ونموذج كائن المستند الافتراضي، وبنية المكونات
كثيراً ما يُساء فهم نموذج DOM الافتراضي على أنه حل سحري، ولكنه في الحقيقة مجرد طبقة مقارنة ذكية.. يحتفظ React بتمثيل في الذاكرة لواجهة المستخدم الخاصة بك ويقارن الشجرة الجديدة بالشجرة القديمة لتحديد عمليات DOM الضرورية بشكل صارم.
حتى مع هذه الكفاءة، فإن كل عملية عرض ومقارنة لا تزال تستغرق وقتًا، لذا فإن هدفك هو تقليل عدد مرات إعادة عرض الأشجار الفرعية الكبيرة.هنا تتقاطع إدارة الحالة وحدود المكونات واستراتيجيات التخزين المؤقت.
أولاً، اختر استراتيجية مناسبة لإدارة حالة التطبيق تتناسب مع مدى تعقيده.حالة React المحلية (useState, useReducer) صغير وبسيط للمكونات الصغيرة، بينما يمكن للمكتبات مثل Redux أو المخازن الخفيفة مثل Zustand مركزة الحالة العالمية الأكثر تعقيدًا بأنماط اشتراك محسّنة.
ثانيًا، قم بتنظيم بياناتك بحيث يتم تجميع البيانات ذات الصلة بشكل منطقي.أحيانًا يعني ذلك دمج عدة useState يتم استدعاء كائن واحد بحيث تكون التحديثات متسقة؛ في حالات أخرى، يكون تقسيم الحالة بحيث لا تجبر الاهتمامات المستقلة بعضها البعض على إعادة العرض أكثر فعالية.
عند تحديث الحالة المستمدة من القيم السابقة، استخدم دائمًا التحديثات الوظيفية. مثل setCount(prev => prev + 1)والحفاظ على عدم قابلية التغيير عن طريق استنساخ المصفوفات والكائنات بدلاً من تعديلها في مكانها. يؤدي هذا إلى سلوك يمكن التنبؤ به ويتوافق بشكل جيد مع التخزين المؤقت والمكونات النقية.
من القواعد المفيدة التي يمكن اتباعها هي إبقاء الولاية محلية قدر الإمكانكلما ارتفع مستوى تخزين قيمة الحالة في الشجرة، زاد عدد المكونات التي ستُعاد عرضها عند تغييرها. أما نقل الحالة إلى المكونات التي تستخدمها فعليًا فيحد من نطاق تأثير كل تحديث.
وأخيرًا، قسّم المكونات الكبيرة إلى أجزاء أصغر وأكثر تركيزًا، والتي نادرًا ما تتغير خصائصها.. تعمل مكونات الأوراق المخزنة مؤقتًا ذات الخصائص الثابتة على تقليل كمية DOM الافتراضي الذي يحتاجه React للمقارنة وتقصير المسار إلى الحد الأدنى من تحديثات DOM.
تقسيم الكود، والتحميل الكسول، وتحسين تحميل الأصول
يُعد حجم حزمة جافا سكريبت عاملاً رئيسياً في ضعف الأداء، خاصة على شبكات الهاتف المحمول.إذا استغرقت حزمة React الخاصة بك عدة ثوانٍ للتنزيل والتحليل، فسوف يغادر المستخدمون الموقع قبل أن يروا واجهة المستخدم الجميلة الخاصة بك.
تقسيم الكود باستخدام React.lazy و Suspense يساعد ذلك من خلال تحميل المكونات عند الطلب بدلاً من شحن كل شيء مقدماًبدلاً من تجميع كل ميزة في الحمولة الأولية، يمكنك استيراد الأجزاء المطلوبة فقط لمسارات أو تفاعلات محددة بشكل ديناميكي.
تتمثل إحدى الاستراتيجيات الشائعة في تقسيم المسارحيث تمثل كل صفحة جزءًا مستقلًا، ولا يتم تحميلها إلا عند انتقال المستخدم إليها. يمكنك التوسع أكثر وتقسيم مكونات الميزات الكبيرة أو اللوحات قليلة الاستخدام، طالما أنك تغلفها بـ Suspense مع واجهة مستخدم احتياطية مناسبة.
ينطبق التحميل الكسول أيضًا على الصور. مضيفا loading="lazy" إلى <img> تؤجل الوسوم تحميل الصور الموجودة أسفل الجزء المرئي من الصفحة حتى تظهر عند التمرير، مما يوفر عرض النطاق الترددي ويسرع عملية الرسم الأولية. وللحصول على تأثيرات أكثر تقدماً، يمكن استخدام مكتبات مثل... react-lazy-load-image-component يدعم هذا النظام العناصر النائبة الضبابية والتحميل التدريجي.
عند تطبيق تقسيم التعليمات البرمجية، من المهم تحقيق التوازن بين أحجام الأجزاء وتجربة المستخدم.قد يؤدي الإفراط في تقسيم البيانات إلى إنشاء عدد كبير جدًا من الطلبات الصغيرة، بينما يؤدي التقليل من تقسيمها إلى حزمة أولية ضخمة. لذا، تُعدّ آليات النسخ الاحتياطي الجيدة وحدود الخطأ حول المكونات الكسولة ضرورية لتجنب تعطل التطبيق بالكامل نتيجةً لفشل طلبات الشبكة.
العرض من جانب الخادم، ومكونات خادم React، وإجراءات الخادم
يقوم العرض من جانب الخادم (SSR) بعرض تطبيق React الخاص بك على الخادم وإرسال HTML إلى العميل، مما يمكن أن يحسن بشكل كبير من الأداء الملحوظ وتحسين محركات البحثيرى المستخدمون المحتوى المفيد بشكل أسرع، ويمكن لمحركات البحث فهرسة صفحاتك بشكل أكثر موثوقية.
تُسهّل أُطر العمل مثل Next.js استخدام SSR و HTML المتدفق للتطبيقات اليومية. تقوم بجلب البيانات على الخادم، وعرض المكونات في HTML - أحيانًا حتى كتدفق - ثم تقوم بترطيب هذا الترميز على العميل بحيث يصبح تفاعليًا.
بالإضافة إلى تقنية SSR الكلاسيكية، تقوم مكونات خادم React بنقل المزيد من منطق واجهة المستخدم إلى جانب الخادم.مما يتيح لك عرض مكونات لا تُرسل إلى العميل مطلقًا. وهذا بدوره يقلل بشكل كبير من حجم حزمة العميل ويبسط عملية جلب البيانات، حيث يمكن لمكونات الخادم استدعاء قواعد البيانات أو واجهات برمجة التطبيقات مباشرةً.
تُوسّع إجراءات الخادم هذه الفكرة من خلال السماح لك بتعريف وظائف تعمل على الخادم ولكن يتم تشغيلها من مكونات العميل.. هذا يلغي الكثير من نقاط نهاية REST النمطية أو معالجات API المخصصة ويمكن أن يبسط كيفية التعامل مع عمليات التغيير وإرسال النماذج والعمليات الأخرى ذات الحالة.
عند استخدامها معًا، توفر لك تقنيات SSR ومكونات الخادم وإجراءات الخادم مجموعة واسعة من استراتيجيات العرض.: يمكن بث المحتوى المهم بسرعة من الخادم، وتبقى العمليات المنطقية الثقيلة بعيدة عن العميل، ويقوم وقت تشغيل React بربط كل شيء معًا في تجربة مستخدم متماسكة.
تفريغ المهام الثقيلة باستخدام Web Workers
حتى أفضل بنية React مُحسّنة ستعاني من التقطيع إذا قمت بتشغيل مهام كثيفة الاستخدام لوحدة المعالجة المركزية على الخيط الرئيسيتؤدي العمليات الحسابية المكلفة إلى عرقلة عملية العرض، وتأخير معالجة الأحداث، وجعل تطبيقك يبدو غير مستجيب.
توفر تقنية Web Workers طريقة لنقل تلك المهام الثقيلة إلى سلسلة عمليات خلفيةتقوم بإرسال البيانات إلى العامل، وتتركه يقوم بمعالجة الأرقام أو معالجة مجموعات البيانات الكبيرة، ثم تتلقى النتيجة مرة أخرى عبر تمرير الرسائل، مما يترك الخيط الرئيسي حراً للتعامل مع تحديثات واجهة المستخدم.
تشمل أعباء العمل النموذجية لعمال الويب معالجة البيانات، ومعالجة الصور، والتحليلات في الوقت الفعلي، أو عمليات المحاكاة المعقدة.على سبيل المثال، غالبًا ما تقوم الألعاب المبنية باستخدام حزمة الويب بتفويض منطق اللعبة الأساسي إلى عامل بينما يتم تخصيص الخيط الرئيسي للعرض ومعالجة المدخلات.
يتضمن دمج عامل مع React إنشاء ملف نصي منفصل، والاستماع إلى onmessage داخل العامل ونشر الرسائل من مكوناتكفي المكون، تقوم بإنشاء العامل، وإرسال المدخلات إليه باستخدام postMessage وتحديث الحالة عند الاستجابة، ومن الأفضل تنظيف العامل عند إلغاء تحميل المكون.
يمكن لمكتبات مثل Comlink أو workerize أو إضافات bundler تبسيط هذا النمط من خلال تجريد عملية تمرير الرسائل منخفضة المستوى ومنحك واجهة برمجة تطبيقات تشبه استدعاء الدوال غير المتزامنة، وهو أمر يسهل فهمه في قاعدة بيانات React.
أهم المقاييس التي تركز على المتصفح والمستخدم والتي يجب مراقبتها
على مستوى أعلى، يتم عادةً تتبع أداء الويب بشكل عام باستخدام مقاييس تركز على المستخدم مثل أول عرض للمحتوى (FCP)، وأكبر عرض للمحتوى (LCP)، ووقت التفاعل (TTI). تُعطي هذه المؤشرات فكرة عن مدى سرعة رؤية المستخدمين للمحتوى ومدى سرعة تفاعلهم معه.
تهدف تطبيقات React الصحية إلى تحقيق زمن تحميل الصفحة الأولى (FCP) أقل من 1.8 ثانية تقريبًا، وزمن تحميل الصفحة الأخيرة (LCP) أقل من 2.5 ثانية تقريبًا، وزمن عرض الصفحة (TTI) أقل بكثير من 4 ثوانٍ على الأجهزة العادية.مع ذلك، قد تختلف الحدود الدقيقة باختلاف المشروع. إذا تجاوزت هذه الأرقام باستمرار، فهذا مؤشر على أن حزم البيانات أو استراتيجية العرض أو أوقات استجابة الخادم لديك تحتاج إلى تحسين.
تساعدك أدوات مثل Lighthouse وWebPageTest ولوحة أداء Chrome على قياس هذه المقاييس في بيئات الاختبار الاصطناعية.للحصول على رؤية واقعية، تقوم أدوات مراقبة المستخدم الحقيقي (RUM) مثل SpeedCurve و Datadog و LogRocket أو Sentry بتتبع جلسات المستخدم الفعلية وربط التجارب البطيئة بتغييرات التعليمات البرمجية.
تتكامل واجهة برمجة تطبيقات Profiler الخاصة بـ React بسلاسة مع هذه الصورةيمكنك تغليف أجزاء من شجرتك بـ <Profiler>قم بتسجيل عمليات العرض البطيئة وربطها بمسارات المستخدم المحددة. عند استخدامها جنبًا إلى جنب مع مراقبة الواجهة الخلفية والشبكة، فإن هذا يمنحك رؤية شاملة لأداء النظام.
سير عمل عملي للفريق لتحسين الأداء
في المشاريع الحقيقية، يكون تحسين الأداء أكثر فعالية عند التعامل معه كعملية متكررة بدلاً من كونه عملية تنظيف لمرة واحدة.تساعد حلقة بسيطة من أربع مراحل - تحديد، والتحقيق، والتنفيذ، والتأكيد - على منع التحسينات الجزئية العشوائية والحفاظ على تركيز الجهود حيثما تكون مهمة.
يعني التحديد استخدام أدوات تحليل البيانات والمقاييس وتقارير المستخدمين للعثور على أعراض محددة. مثل بطء تحميل الصفحات، وانخفاض معدل الإطارات، أو ارتفاع معدل التخلي عن التصفح خلال مراحل معينة. أنت تريد مشاكل قابلة للقياس، لا مجرد حدس.
يتعمق التحقيق في السبب الجذريقد تحتوي الصفحة على عشرات الإطارات المضمنة المخفية، أو قد يُعاد عرض مكون معين بشكل متكرر للغاية، أو يتم تحميل مكتبة ضخمة من مورد خارجي في كل مسار. هنا، عليك الاعتماد بشكل كبير على أداة تحليل أداء React DevTools وخط زمني Chrome.
التنفيذ هو المرحلة التي يتم فيها تطبيق الإصلاحات المستهدفة.— تخزين بيانات مكون نشط، أو محاكاة قائمة طويلة، أو تقسيم حزمة، أو تفريغ العمل إلى عامل ويب، أو تفعيل عرض الصفحة من جانب الخادم (SSR) لصفحات معينة. يجب أن يكون كل تغيير صغيرًا بما يكفي لفهمه.
التأكيد هو الخطوة الأخيرة، وغالبًا ما يتم تجاهله. تقوم بإعادة تشغيل سيناريوهات التنميط الخاصة بك والتحقق من لوحات معلومات المقاييس الخاصة بك للتأكد من أن التغيير قد حسّن الأرقام بالفعل ولم يُدخل تراجعات في أماكن أخرى من النظام.
عندما تجمع بين بناء React الصحيح، والتخزين المؤقت المدروس، وممارسات الحالة الثابتة، ومحاكاة القوائم، وتقسيم الكود الاستراتيجي، وSSR، وWeb Workers، والقياس المستمر، ستحصل في النهاية على تطبيقات React تظل سريعة الاستجابة حتى مع ازدياد تعقيدها.; لا تتعلق التقنيات المذكورة أعلاه بالتعديل الدقيق المبكر، بل ببناء بنية يظل فيها الأداء نتيجة طبيعية بدلاً من كونه صراعًا مستمرًا.

