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