توضّح هذه الدراسة الحالة سير العمل المفصّل لتحديد الأخطاء وحلّها وتحسين ملف INP
في React الذي تستخدمه شركة Trendyol من خلال الاستفادة من أدوات Google، مثل إحصاءات سرعة التحميل (PSI) في PageSpeed وChrome DevTools وscheduler.yield
API.
إنّ صفحة بيانات المنتج (PLP) وصفحة تفاصيل المنتج (PDP) هما مكوّنان رئيسيان لأي موقع إلكتروني للتجارة الإلكترونية. غالبًا ما تأتي زيارات التجارة الإلكترونية من صفحات بيانات المنتجات، سواء من خلال حملات البريد الإلكتروني أو وسائل التواصل الاجتماعي أو الإعلانات. نتيجةً لذلك، من المهم التأكّد من أنّ تجربة PLP مصمّمة بعناية لتقليل الوقت الذي يستغرقه إتمام عملية الشراء. إنّ منح الأولوية لجودة تجربة المستخدم أمر ضروري لتحقيق النجاح. لقد كشفت الإصدارات البحثية، مثل Milliseconds Make Millions، عن التأثير الكبير لأداء الويب في استعداد المستهلكين لإنفاق الأموال والتفاعل مع العلامات التجارية على الإنترنت.
Trendyol هي منصة للتجارة الإلكترونية تضمّ حوالي 30 مليون عميل و 240,000 بائع، ما دفعنا إلى أن نصبح أوّل نشاط تجاري في تركيا بقيمة تزيد عن 10 مليارات دولار أمريكي، وإحدى أهم منصات التجارة الإلكترونية في العالم.
ولتحقيق هدفها المتمثل في تقديم أفضل تجربة ممكنة للمستخدم على نطاق واسع، مع الحفاظ على مرونة المحتوى والعمل باستخدام إصدار قديم من React، ركّزت Trendyol على مقياس مدى استجابة الصفحة لتفاعلات المستخدم (INP) كمقياس رئيسي لتحسين الأداء. توضّح هذه الدراسة الحالة رحلة Trendyol في تحسين مقياس INP في صفحة المنتج في خدمة مقارنة الأسعار (PLP)، ما أدّى إلى انخفاض بنسبة %50 في مقياس INP وزيادة بنسبة %1 في مقياس النشاط التجاري لنتائج البحث .
عملية التحقيق في طلبات الحصول على إذن بالوصول إلى البيانات (INP) في Trendyol
يقيس مقياس INP استجابة الموقع الإلكتروني للبيانات التي يُدخلها المستخدم. يشير مقياس INP الجيد إلى أنّ المتصفّح قادر على الاستجابة بسرعة وموثوقية لجميع بيانات المستخدمين وإعادة رسم الصفحة، ما يشكّل مكوّنًا أساسيًا لتوفير تجربة مستخدم جيدة.
بدأت Trendyol لتحسين INP على PLP بتحليل شامل لتجربة المستخدم قبل إجراء أي تحسينات. استنادًا إلى تقرير PSI، تبيّن أنّ تجربة المستخدم الحقيقية لهذه الخدمة بلغ INP 963 ملّي ثانية على الأجهزة الجوّالة، كما هو موضّح في الشكل التالي.
لضمان سرعة الاستجابة الجيدة، يجب أن يهدف مالكو المواقع الإلكترونية إلى الحصول على قيمة INP أدنى من أو مساوية 200 ملي ثانية، ما يعني أنّ قيمة INP لموقع Trendyol كانت في ذلك الوقت ضمن النطاق "الضعيف".
لحسن الحظ، يوفّر PSI كلاً من بيانات الاستخدام الفعلي للصفحات المضمّنة في تقرير تجرب مستخدمي Chrome (CrUX) وبيانات تشخيص مفصّلة في المختبر. عند الاطّلاع على بيانات المختبر، أشار تدقيق وقت تنفيذ JavaScript من Lighthouse إلى أنّ النص البرمجي search-result-v2
كان يشغل سلسلة التعليمات الرئيسية لوقت أطول من النصوص البرمجية الأخرى على الصفحة.
لتحديد نقاط الأداء المنخفضة في الواقع، استخدمنا لوحة الأداء في "أدوات مطوري البرامج" في Chrome لتحديد المشاكل وحلّها في تجربة PLP وتحديد مصدر المشكلة. إنّ محاكاة أداء الأجهزة الجوّالة مع تباطؤ وحدة المعالجة المركزية (CPU) بمقدار 4 مرات ضمن "أدوات مطوري البرامج في Chrome" أتاحت مهمة تتراوح مدّتها بين 700 و900 مللي ثانية في سلسلة التعليمات الرئيسية. إذا كانت سلسلت المحادثات الرئيسية مشغولة بمهام أخرى لأكثر من 50 مللي ثانية، قد لا تتمكّن من الاستجابة لبيانات المستخدم في الوقت المناسب، ما يؤدي إلى تجربة مستخدم سيئة.
حدثت المهمة الأطول بسبب طلب استدعاء Intersection Observer API في ملف برمجي لنتائج البحث داخل مكوّن React. في هذه المرحلة، بدأنا ننظر في تقسيم هذه المهمة الطويلة إلى أجزاء صغيرة لمنح المتصفّح المزيد من فرص الاستجابة للعمل ذات الأولوية الأعلى، بما في ذلك تفاعلات المستخدمين.
تبيّن أنّ استخدام عملية setState
التي تؤدي إلى إعادة عرض React
داخل ردّ اتصال Intersection Observer يتطلّب تكلفة عالية،
وقد يتسبب ذلك في حدوث مشاكل على الأجهزة المنخفضة المستوى بسبب احتلال السلسلة الرئيسية
لوقت طويل جدًا.
إحدى الطرق التي استخدمها مطوّرو البرامج لتقسيم المهام إلى مهام أصغر تتضمن setTimeout
. لقد استخدمنا هذه التقنية لتأجيل تنفيذ طلب
setState
إلى مهمة منفصلة. على الرغم من أنّ setTimeout
يسمح بتأجيل تنفيذ
JavaScript، إلا أنّه لا يقدّم أيّ تحكم في الأولوية. وقد أدّى ذلك
إلى انضمامنا إلى الإصدار التجريبي من scheduler.yield
في محاولة لضمان
مواصلة تنفيذ البرنامج النصي بعد التنازل عن سلسلة التعليمات الرئيسية:
/*
* Yielding method using scheduler.yield, falling back to setTimeout:
*/
async function yieldToMain() {
if('scheduler' in window && 'yield' in scheduler) {
return await scheduler.yield();
}
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
/*
* Yielding to the main thread before changing the state of the component:
*/
const observer = new IntersectionObserver((entries) => {
entries.forEach(handleIntersection);
const maxNumberOfEntries = Math.max(...this.intersectingEntries);
if (Number.isFinite(maxNumberOfEntries)) {
await this.yieldToMain();
this.setState({ count: maxNumberOfEntries });
}
}, { threshold: 0.5 });
من خلال إضافة هذه الطريقة إلى رمز PLP، تم تحسين INP، إذ تم تقسيم المهمة الطويلة الرئيسية إلى سلسلة من المهام الأصغر حجمًا، ما يسمح بإجراء عمل ذي أولوية أعلى، مثل تفاعلات المستخدم وأعمال العرض اللاحقة، في وقت أقرب مما كان من الممكن أن يحدث بخلاف ذلك.
يُرجى العِلم أنّ Trendyol تستخدم إطار عمل PuzzleJs لتنفيذ بنية واجهة أمامية متناهية الصغر باستخدام React v16.9.0. يمكن تحقيق الأداء نفسه باستخدام React 18، ولكن يتعذّر على Trendyol الترقية في الوقت الحالي لعدة أسباب.
نتائج النشاط التجاري
لقياس تأثير تحسين INP الذي تم تنفيذه، أجرينا اختبار أ/ب لمحاولة معرفة مدى تأثُّر مقاييس النشاط التجاري. بشكل عام، أدّت التغييرات التي أجريناها على صفحة قائمة المنتجات إلى تحسّن كبير، بما في ذلك انخفاض معدّل النقر إلى الشراء بنسبة %50 وزيادة بنسبة %1 في معدّلات النقر من صفحة البيانات إلى صفحة تفاصيل المنتج لكل جلسة مستخدِم. في الشكل التالي، يمكنك الاطّلاع على كيفية تحسين مقياس INP في ملف picuture loaded page (ملف PLP) بمرور الوقت:
الخاتمة
إنّ تحسين مقياس INP هو عملية معقّدة ومتكرّرة، ولكن يمكن تسهيلها من خلال سير عمل واضح. تعتمد طريقة بسيطة لتصحيح الأخطاء وتحسين INP على موقعك الإلكتروني على ما إذا كنت تجمع بيانات الميدان الخاص بك أم لا. إذا لم يكن الأمر كذلك، يُعدّ PSI وLighthouse نقطة بداية جيدة. بعد تحديد الصفحات التي تتضمّن مشاكل، يمكنك استخدام أدوات مطوّري البرامج للتوغّل أكثر في محاولة إعادة تكرار المشاكل.
إنّ التنازل عن سلسلة المهام الرئيسية من حين لآخر لمنح المتصفّح المزيد من
فرص لتنفيذ المهام الملحّة سيجعل موقعك الإلكتروني أكثر استجابة، ما يضمن
حصول عملائك على تجربة مستخدم أفضل. تسهّل واجهات برمجة التطبيقات الأحدث المخصّصة للجدولة، مثل scheduler.yield()
، هذه المهمة.
نشكر بشكل خاص "جيريمي واغنر" و"باري بولارد" و"حسين جيرديه" من Google وفريق المهندسين في Trendyol على مساهمتهم في هذا العمل.