دراسة حالة واقعية لتحسين أداء React SPA.
لا يقتصر أداء موقع الويب على وقت التحميل فحسب. من المهم توفير تجربة سريعة وسريعة الاستجابة للمستخدمين، وخاصةً بالنسبة إلى تطبيقات الإنتاجية على الكمبيوتر المكتبي التي يستخدمها الأشخاص يوميًا. خضع الفريق الهندسي في Recruit Technologies لمشروع إعادة الهيكلة لتحسين أحد تطبيقات الويب لديهم، وهو AirSHIFT، لتحسين أداء البيانات التي يُدخلها المستخدمون. إليك كيف فعلوا ذلك.
استجابة بطيئة، إنتاجية أقل
AirSHIFT هو تطبيق ويب على كمبيوتر مكتبي يساعد مالكي المتاجر، مثل المطاعم والمقاهي، في إدارة عمل نوبات العمل للموظفين. تم تصميم التطبيق المكوّن من صفحة واحدة باستخدام React وهو وتوفّر العديد من الميزات المفيدة للعملاء، منها جداول على شكل مربّعات خاصة بجداول نوبات العمل المُرتّبة حسب اليوم والأسبوع والشهر وغير ذلك.
بعد أن أضاف فريق هندسة Recruit Technologies ميزات جديدة إلى تطبيق AirSHIFT، بدأوا في رؤية المزيد من الملاحظات بشأن بطء الأداء. قال المدير الهندسي لنظام AirSHIFT، يوسوكي فوروكاوا:
في دراسة بحثية حول المستخدمين، صدمنا عندما قال أحد مالكي المتاجر إنّها ستترك مقعدها لتحضير القهوة بعد النقر على زر معيّن، وذلك لقضاء وقت ممتع أثناء الانتظار إلى حين تحميل منضدة نوبات العمل.
بعد إجراء البحث، أدرك الفريق الهندسي أن العديد من المستخدمين كانوا يحاولون تحميل جداول متغيرات ضخمة على أجهزة كمبيوتر ذات مواصفات منخفضة، مثل كمبيوتر محمول Celeron M بسرعة 1 غيغاهرتز من قبل 10 سنوات.
كان تطبيق AirSHIFT يحجب سلسلة التعليمات الرئيسية باستخدام نصوص برمجية باهظة الثمن، لكن الفريق الهندسي لم يدرك مدى تكلفة النصوص البرمجية لأنها كانت تطور واختبارها على أجهزة كمبيوتر ذات مواصفات غنية ومزودة باتصالات Wi-Fi سريعة.
بعد تحديد أداء الشركة في "أدوات مطوري البرامج في Chrome" مع تفعيل تقييد وحدة المعالجة المركزية (CPU) والشبكة، اتّضح أنّ تحسين الأداء كان مطلوبًا. وقد شكلت فرقة AirSHIFT فريق عمل لمعالجة هذه المشكلة. إليك 5 أشياء ركزوا عليها لجعل تطبيقهم أكثر استجابة لإدخالات المستخدم.
1- المحاكاة الافتراضية للجداول الكبيرة
يتطلب عرض جدول shift خطوات متعددة مكلفة: إنشاء نموذج العناصر في المستند الافتراضي (DOM) وعرضه على الشاشة بما يتناسب مع عدد الموظفين والخانات الزمنية. على سبيل المثال، إذا كان مطعم يضم 50 عضوًا يعمل وأراد التحقق من جدول نوبات العمل الشهرية الخاصة به، فسيكون جدولاً مكونًا من 50 (عضو) مضروبًا في 30 (يوم) مما سيؤدي إلى عرض 1500 مكون من مكونات الخلية. وهذه العملية مكلفة للغاية، خاصةً للأجهزة ذات المواصفات المنخفضة. في الواقع، كانت الأمور أسوأ. من البحث الذي تعلموا منه أن هناك متاجر تدير 200 موظف، وتتطلب حوالي 6000 مكون من مكونات الخلية في جدول شهري واحد.
ولخفض تكلفة هذه العملية، قامت AirSHIFT بمحاكاة جدول التحول. يثبِّت التطبيق الآن المكونات داخل إطار العرض فقط ويلغي تثبيت المكونات التي تظهر خارج الشاشة.
في هذه الحالة، استخدمت ميزة AirSHIFT أسلوب الاستجابة الافتراضية بسبب متطلبات تفعيل جداول الشبكة الثنائية الأبعاد المعقّدة. تستكشف الشركة أيضًا طرقًا لتحويل عملية التنفيذ إلى نص باستخدام مهلة الاستجابة البسيطة في المستقبل.
النتائج
أدت المحاكاة الافتراضية للجدول وحده إلى تقليل وقت البرمجة النصية بمقدار 6 ثوانٍ (عند بطء وحدة المعالجة المركزية (CPU) 4 مرات + الجيل الثالث السريع من جهاز Macbook Pro). كان هذا هو التحسين الأكثر تأثيرًا في الأداء في مشروع إعادة الهيكلة.
2. التدقيق باستخدام واجهة برمجة تطبيقات User Timing
بعد ذلك، أعاد فريق AirSHIFT إعادة بناء النصوص البرمجية التي كانت تعمل على مدخلات المستخدم. يتيح الرسم البياني الوافي لـ أدوات مطوري البرامج في Chrome تحليل ما يحدث فعليًا في سلسلة التعليمات الرئيسية. لكن فريق AirSHIFT وجد أنه من الأسهل تحليل نشاط التطبيقات بناءً على دورة حياة React.
يوفّر React 16 بيانات تتبُّع الأداء الخاصة به من خلال User Timing API التي يمكنك الاطّلاع عليها من خلال قسم التوقيت في "أدوات مطوري البرامج في Chrome". استخدمت AirSHIFT قسم "التوقيتات" للعثور على منطق غير ضروري التي يتم تشغيلها في أحداث دورة حياة React.
النتائج
اكتشف فريق AirSHIFT أنّ عملية تسوية شجرة التفاعل غير الضرورية كانت تحدث قبل كل عملية انتقال في المسار. هذا يعني أن React كان يحدّث جدول التحول بشكل غير ضروري قبل عمليات التنقل. تسبب تحديث حالة Redux غير الضروري الذي تسبب في هذه المشكلة. وقد ساعد إصلاحه على توفير 750 ملي ثانية تقريبًا من وقت البرمجة النصية. أجرت AirSHIFT تحسينات دقيقة أخرى أيضًا وأدّت إلى انخفاض إجمالي وقت البرمجة النصية بمقدار ثانية واحدة.
3- طريقة "التحميل الكسول" للمكوّنات ونقل المنطق المكلّف إلى مستخدمي الويب
يحتوي AirSHIFT على تطبيق دردشة مدمج. يتواصل العديد من مالكي المتاجر مع موظفيهم من خلال المحادثة أثناء الاطّلاع على جدول وردية، ما يعني أنّ أحد المستخدمين قد يكتب رسالة أثناء تحميل الجدول. إذا كانت سلسلة التعليمات الرئيسية مشغولة بنصوص برمجية تعرض الجدول، قد تكون البيانات التي أدخلها المستخدم رديئة.
لتحسين هذه التجربة، تستخدم ميزة AirSHIFT الآن الإجراءَين React.lazy وSsuspense لعرض العناصر النائبة لمحتوى الجدول مع التحميل الكسول للمكوّنات الفعلية.
نقل فريق AirSHIFT أيضًا بعضًا من المصطلحات المنطقية للأنشطة التجارية المكلفة داخل المكوّنات التي يتم تحميلها ببطء إلى عاملي الويب. أدى ذلك إلى حل مشكلة البيانات غير المحتملة لإدخال المستخدم عن طريق تحرير سلسلة التعليمات الرئيسية بحيث يمكن التركيز على الاستجابة لإدخال المستخدم.
يواجه عادةً المطوّرون تعقيدات في التعامل مع العاملين، ولكن هذه المرة بذلت شركة Comlink المهام الصعبة لهم. فيما يلي الكود الزائف لكيفية تشغيل AirSHIFT لإحدى العمليات الأكثر تكلفة التي تمت: حساب تكاليف العمالة الإجمالية.
في App.js، استخدِم React.lazy وSuspense لعرض المحتوى الاحتياطي أثناء التحميل
/** App.js */
import React, { lazy, Suspense } from 'react'
// Lazily loading the Cost component with React.lazy
const Hello = lazy(() => import('./Cost'))
const Loading = () => (
<div>Some fallback content to show while loading</div>
)
// Showing the fallback content while loading the Cost component by Suspense
export default function App({ userInfo }) {
return (
<div>
<Suspense fallback={<Loading />}>
<Cost />
</Suspense>
</div>
)
}
في مكوّن التكلفة، استخدِم comlink لتنفيذ منطق الحساب
/** Cost.js */
import React from 'react';
import { proxy } from 'comlink';
// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default async function Cost({ userInfo }) {
// execute the calculation in the worker
const instance = await new WorkerlizedCostCalc();
const cost = await instance.calc(userInfo);
return <p>{cost}</p>;
}
تنفيذ العمليات الحسابية التي يتم تنفيذها في العامل وعرضه من خلال رابط
// WorkerlizedCostCalc.js
import { expose } from 'comlink'
import { someExpensiveCalculation } from './CostCalc.js'
// Expose the new workerlized calc function with comlink
expose({
calc(userInfo) {
// run existing (expensive) function in the worker
return someExpensiveCalculation(userInfo);
}
}, self);
النتائج
وعلى الرغم من القدر المحدود من المنطق الذي استخدموه كإصدار تجريبي، حوّلت تقنية AirSHIFT حوالي 100 ملي ثانية من لغة JavaScript من سلسلة التعليمات الرئيسية إلى سلسلة التعليمات (تمت محاكاتها باستخدام وحدة المعالجة المركزية 4x).
تستكشف ميزة AirSHIFT حاليًا ما إذا كان بإمكانها إجراء تحميل بطيء لمكوّنات أخرى وتفريغ المزيد من البيانات المنطقية لموظفي الويب للحدّ من البيانات غير المحتملة.
4. ضبط ميزانية للأداء
بعد تنفيذ جميع هذه التحسينات، كان من الضروري التأكّد من استمرار أداء التطبيق مع مرور الوقت. يستخدم AirSHIFT الآن bundlesize لعدم تجاوز الحجم الحالي لملف JavaScript وCSS. وبالإضافة إلى تحديد هذه الميزانيات الأساسية، أنشأ الفريق لوحة معلومات تعرض نسبًا مئوية مختلفة من وقت تحميل جدول التحول للتحقق مما إذا كان التطبيق يعمل حتى في الظروف غير المثالية.
- يتم الآن قياس وقت إكمال النص البرمجي لكل حدث Redux
- يتم جمع بيانات الأداء في Elasticsearch.
- يتم تصوّر الأداء في الشرائح المئوية 10 و25 و50 و75 لكل حدث باستخدام Kibana.
تراقب ميزة AirSHIFT الآن حدث تحميل جدول Shift للتأكّد من اكتماله خلال 3 ثوانٍ للمستخدمين من الشريحة المئوية الخامسة والسبعين. هذه ميزانية غير ملزمة في الوقت الحالي، لكنهم يفكرون في الإشعارات التلقائية من خلال Elasticsearch عندما يتجاوزون ميزانيتهم.
النتائج
من الرسم البياني أعلاه، يمكنك معرفة أنّ AirSHIFT أصبح الآن يبلغ في الغالب الميزانية البالغة 3 ثوانٍ للمستخدمين من الشريحة المئوية الخامسة والسبعين، كما يحمِّل أيضًا جدول shift في غضون ثانية واحدة للمستخدِمين من الشريحة المئوية الخامسة والعشرين. من خلال التقاط بيانات أداء RUM من ظروف وأجهزة مختلفة، يمكن لتقنية AirSHIFT الآن التحقق مما إذا كان إصدار ميزة جديدة يؤثر بالفعل في أداء التطبيق أم لا.
5- فعاليات الهاكاثون في الأداء
وعلى الرغم من أنّ جميع جهود تحسين الأداء هذه كانت مهمة ومؤثرة، ليس من السهل دائمًا على فِرق الهندسة والشركات إعطاء الأولوية للتطوير غير الوظيفي. يتمثل جزء من التحدي في أنه لا يمكن التخطيط لبعض تحسينات الأداء هذه. فهي تتطلب التجربة والقدرة على التجربة والخطأ.
تُجري AirSHIFT الآن فعاليات هاكاثون داخلية قائمة على الأداء لمدة يوم واحد للسماح للمهندسين بالتركيز فقط على الأعمال ذات الصلة بالأداء. في أحداث الهاكاثون هذه، يزيلون كل القيود ويحترمون إبداع المهندسين، مما يعني أن أي تنفيذ يساهم في السرعة يستحق الاهتمام. لتسريع فترة الهاكاثون، قسّمت ميزة AirSHIFT المجموعة إلى فِرق صغيرة، ويتنافس كل فريق لمعرفة الفريق الذي يمكنه تحقيق أكبر تحسين في نتيجة أداء Lighthouse. تشهد الفرق منافسة شديدة! 🔥
النتائج
نهج الهاكاثون جيد بالنسبة لهم.
- يمكن اكتشاف المؤثِّرات السلبية في الأداء بسهولة من خلال تجربة أساليب متعددة أثناء الهاكاثون وقياس كلّ منها باستخدام Lighthouse.
- بعد انتهاء الهاكاثون، أصبح من السهل إقناع الفريق بالتحسين الذي يجب أن يمنحه الأولوية لإصدار الإنتاج.
- إنها أيضًا طريقة فعالة للتشجيع على أهمية السرعة. يمكن لكل مشارك فهم الارتباط بين كيفية الترميز وكيف يؤدي إلى الأداء.
من الآثار الجانبية الجيدة أن العديد من الفرق الهندسية الأخرى داخل Recruit أبدى اهتمامه بهذا النهج العملي وبدأ فريق AirSHIFT الآن في إقامة مسابقات الهاكاثون المتعددة السرعة داخل الشركة.
ملخّص
لم تكن هذه هي الرحلة الأسهل بالنسبة إلى AirSHIFT، لكنّها أثمرت بالتأكيد عن هذه التحسينات. أصبح الآن بإمكان AirSHIFT تحميل جدول التحول في غضون ثانية ونصف، ما يعني تحسُّنًا بمقدار 6 أضعاف مقارنةً بأدائها قبل المشروع.
بعد إطلاق تحسينات الأداء، قال أحد المستخدمين:
شكرًا جزيلاً على سرعة تحميل جدول Shift. أصبح ترتيب ورديات العمل أكثر كفاءة بكثير الآن.