בניתוח המקרה הזה מתוארת תהליך עבודה מפורט של ניפוי באגים ושיפור INP ב-React, שבו נעשה שימוש ב-Trendyol. התהליך מתבצע באמצעות כלים של Google כמו PageSpeed Insights (PSI), Chrome DevTools ו-scheduler.yield
API.
שני רכיבים קריטיים בכל אתר מסחר אלקטרוני הם דף כרטיס המוצר (PLP) ודף פרטי המוצר (PDP). תנועה במסחר אלקטרוני מגיעה לעיתים קרובות מדפי כרטיסי מוצר, דרך קמפיינים באימייל, רשתות חברתיות או מודעות. לכן חשוב לוודא שחוויית השימוש בדף המוצר תוכננה בקפידה כדי לקצר את משך הזמן הנדרש לביצוע רכישה. כדי להצליח, חשוב לתת עדיפות לאיכות חוויית המשתמש. במאמרים שפורסמו בכתבי עת, כמו Milliseconds Make Millions, כבר נחשף ההשפעה המשמעותית של ביצועי האתר על הנכונות של הצרכנים להוציא כסף ולנהל אינטראקציה עם מותגים באינטרנט.
Trendyol היא פלטפורמת מסחר אלקטרוני עם כ-30 מיליון לקוחות ו-240,000 מוכרים. הפלטפורמה הזו הפכה אותנו לחברה הראשונה בטורקיה עם שווי של יותר מ-10 מיליארד דולר, ואחת מפלטפורמות המסחר האלקטרוני המובילות בעולם.
כדי להשיג את המטרה של מתן חוויית המשתמש הטובה ביותר האפשרית בקנה מידה נרחב, תוך שמירה על גמישות התוכן ועל עבודה עם גרסת React ישנה יותר, ב-Trendyol התמקדו במהירות התגובה לאינטראקציה באתר (INP) כמדד מפתח לשיפור. בניתוח המקרה הזה מתוארת הדרך שבה Trendyol שיפרה את מדד INP בדף ה-PLP שלה, וכתוצאה מכך הפחיתה ב-50% את מדד INP והגדילה ב-1% את המדד העסקי של תוצאות החיפוש.
תהליך החקירה של Trendyol על ידי INP
המדד INP מודד את רמת הרספונסיביות של אתר לקלט של משתמשים. מדד INP טוב מציין שהדפדפן יכול להגיב במהירות ובצורה אמינה לכל הקלט של המשתמשים ולצייר מחדש את הדף. זהו רכיב מפתח בחוויית משתמש טובה.
התהליך של Trendyol לשיפור INP ב-PLP שלה התחיל בניתוח מעמיק של חוויית המשתמש לפני ביצוע השיפורים. על סמך דוח PSI, חוויית השימוש האמיתית של PLP הייתה עם INP של 963 אלפיות שנייה בנייד, כפי שמוצג באיור הבא.
כדי להבטיח תגובה מהירה, בעלי אתרים צריכים לשאוף ל-INP שנמוך מ-200 אלפיות השנייה או שווה לו. כלומר, באותו זמן, ה-INP של Trendyol היה בטווח 'גרוע'.
למרבה המזל, PSI מספק גם נתוני שטח לדפים שכלולים בדוח לגבי חוויית המשתמש ב-Chrome (CrUX) וגם נתוני אבחון מפורטים של מעבדה. לפי נתוני המעבדה, בדיקת זמן הביצוע של JavaScript ב-Lighthouse העלתה שהתסריט search-result-v2
השתמש ב-thread הראשי במשך זמן רב יותר מאשר תסריטים אחרים בדף.
כדי לזהות צווארי בקבוק בעולם האמיתי, השתמשנו בלוח הביצועים ב-Chrome DevTools כדי לפתור את הבעיה בחוויית השימוש ב-PLP ולזהות את מקור הבעיה. הדמיה של ביצועים בנייד עם האטה של 4x במעבד בכלים למפתחים ב-Chrome חשפה משימה שנמשכת 700-900 אלפיות השנייה בשרשור הראשי. אם השרשור הראשי תפוס במשימות אחרות למשך יותר מ-50 אלפיות שנייה, יכול להיות שהוא לא יוכל להגיב לקלט של משתמשים בזמן, וכתוצאה מכך חוויית המשתמש תהיה גרועה.
המשימה הארוכה ביותר נגרמה על ידי קריאה חוזרת (callback) של Intersection Observer API בסקריפט של תוצאות החיפוש בתוך רכיב React. בשלב הזה התחלנו לבחון את האפשרות לפצל את המשימה הארוכה הזו למקטעים קטנים, כדי לתת לדפדפן יותר הזדמנויות להגיב לעבודה בעדיפות גבוהה יותר – כולל אינטראקציות של משתמשים.
מסתבר שהשימוש בפעולה setState
שמפעילה עיבוד מחדש של React בתוך פונקציית ה-callback של Intersection Observer כרוך בעלות גבוהה, שעלולה להוות בעיה במכשירים ברמה נמוכה כי היא תופסת את השרשור הראשי למשך זמן רב מדי.
אחת מהשיטות שבהן המפתחים השתמשו כדי לפצל משימות למשימות קטנות יותר היא setTimeout
. השתמשנו בשיטה הזו כדי לדחות את הביצוע של הקריאה ל-setState
למשימה נפרדת. אמנם setTimeout
מאפשר לדחות את ביצוע ה-JavaScript, אבל הוא לא מספק שליטה על העדיפות. לכן הצטרפנו לגרסת המקור של תקופת הניסיון של scheduler.yield
כדי להבטיח את המשך ביצוע הסקריפט אחרי העברת השליטה ל-thread הראשי:
/*
* 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, הרצנו בדיקת A/B כדי לראות איך המדדים העסקיים הושפעו. באופן כללי, השינויים שערכנו בדף פרטי המוצר הובילו לשיפור משמעותי, כולל ירידה של 50% ב-INP ועלייה של 1% בשיעורי הקליקים מדף כרטיסי המוצר לדף פרטי המוצר לכל סשן של משתמש. בתרשים הבא אפשר לראות איך ערך ה-INP השתפר ב-PLP לאורך זמן:
סיכום
אופטימיזציה של קובצי INP היא תהליך מורכב וחוזר, אבל אפשר להקל עליו באמצעות תהליך עבודה ברור. הגישה הפשוטה לניפוי באגים ולשיפור ה-INP של האתר תלויה בכך שאתם אוספים נתוני שדה משלכם. אם לא, PSI ו-Lighthouse הם נקודת התחלה טובה. אחרי שמזהים דפים עם בעיות, אפשר להשתמש בכלי הפיתוח כדי להעמיק את הבדיקה ולנסות לשחזר את הבעיות.
אם תעבירו את הבעלות על הפעילות לשרשור הראשי מדי פעם כדי לתת לדפדפן יותר הזדמנויות לבצע משימות דחופות, האתר שלכם יהיה רספונסיבי יותר והלקוחות ייהנו מחוויית משתמש טובה יותר. ממשקי API חדשים לניהול תזמון, כמו scheduler.yield()
, מאפשרים לבצע את המשימה הזו בקלות רבה יותר.
תודה מיוחדת ל-Jeremy Wagner, ל-Barry Pollard ול-Houssein Djirdeh מ-Google, ולצוות ההנדסה של Trendyol על התרומה שלהם לעבודה הזו.