תיקון חוסר יציבות בפריסה

הדרכה מפורטת בנושא שימוש ב-WebPageTest לזיהוי בעיות של חוסר יציבות בפריסה ותיקון שלהן.

ריק ויסקומי
ריק ויסקומי

בפוסט קודם שכתבתי על מדידת Cumulative Layout Shift (CLS) ב-WebPageTest. הנתון CLS הוא אוסף של כל השינויים בפריסה. בפוסט הזה חשבתי שיהיה מעניין להתעמק בנתונים ולבדוק כל שינוי פריסה בנפרד בדף, כדי להבין מה יכול לגרום לאי היציבות ולנסות לפתור את הבעיות.

מדידת התנודות בפריסה

באמצעות ה-API של אי יציבות הפריסה, אנחנו יכולים לקבל רשימה של כל האירועים של שינוי הפריסה בדף:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

התוצאה הזו יוצרת מערך של תנודות בפריסה שלא קדמו להם אירועי קלט:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

בדוגמה הזו היה שינוי קטנטן מאוד של 0.01% ב-210 אלפיות השנייה.

כדאי לדעת את הזמן והחומרה של השינוי כדי לזהות את הסיבות האפשריות לשינוי. נחזור אל WebPageTest כדי ליצור סביבת שיעור Lab כדי לבצע בדיקות נוספות.

מדידת השינויים בפריסה ב-WebPageTest

בדומה למדידת CLS ב-WebPageTest, כדי למדוד שינויים ספציפיים בפריסה צריך מדד מותאם אישית. למרבה המזל, התהליך קל יותר עכשיו, כשגרסת Chrome 77 היא יציבה. ה-API של אי יציבות הפריסה מופעל כברירת מחדל, כך שאתם אמורים להיות מסוגלים להפעיל את קטע ה-JS הזה בכל אתר ב-Chrome 77 ולקבל תוצאות באופן מיידי. ב-WebPageTest אפשר להשתמש בדפדפן Chrome שמוגדר כברירת מחדל, בלי לדאוג לגבי דגלים בשורת הפקודה או שימוש ב-Canary.

בואו נשנה את הסקריפט הזה כדי ליצור מדד מותאם אישית עבור WebPageTest:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

ההבטחה בסקריפט הזה מובילה לייצוג JSON של המערך ולא למערך עצמו. הסיבה לכך היא שמדדים מותאמים אישית יכולים להפיק רק סוגי נתונים ראשוניים, כמו מחרוזות או מספרים.

האתר שאשתמש בו בבדיקה הוא ismyhostfastyet.com, אתר שיצרתי כדי להשוות בין ביצועי הטעינה בפועל של מארחי אינטרנט.

זיהוי הסיבות לחוסר יציבות בפריסה

בתוצאות נוכל לראות שהמדד המותאם אישית LayoutShifts מכיל את הערך הבא:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

לסיכום, יש שינוי פריסה יחיד של 34.2% בקצב של 3,087 אלפיות השנייה. כדי לעזור בזיהוי הבעיה, נשתמש בתצוגת רצועת התמונות של WebPageTest.

שני תאים ברצועת השקפים, עם צילומי מסך לפני ואחרי שינוי הפריסה.
שני תאים ברצועת השקפים, מוצגים צילומי מסך לפני ואחרי שינוי הפריסה.

גלילה לסמן של כ-3 שניות ברצועת התמונות מראה לנו בדיוק מה הסיבה לשינוי הפריסה של 34%: הטבלה הצבעונית. האתר מאחזר קובץ JSON באופן אסינכרוני, ולאחר מכן מעבד אותו בטבלה. בהתחלה הטבלה ריקה, לכן צריך להמתין כדי למלא אותה כשהתוצאות נטענות, ולכן הגורם לשינוי.

כותרת גופן אינטרנטי מופיעה משום מקום.
כותרת גופן אינטרנט שמופיע משום מקום.

אבל זה לא הכול. כשיצירת הדף תסתיים בערך של 4.3 שניות, אפשר לראות שה<h1> של הדף 'האם המארח שלי מהיר עדיין?' מופיע משום מקום. הסיבה לכך היא שהאתר משתמש בגופן אינטרנט ולא ביצע פעולות לביצוע אופטימיזציה של הרינדור. נראה שהפריסה לא זזה כשזה קורה, אבל בכל זאת חוויית המשתמש גרועה בגלל שצריך להמתין כל כך הרבה זמן כדי לקרוא את הכותרת.

תיקון חוסר יציבות בפריסה

עכשיו, אחרי שאנחנו יודעים שהטבלה שנוצרת באופן אסינכרוני גורמת לשליש מאזור התצוגה להשתנות, הגיע הזמן לתקן את זה. אין לנו מידע על התוכן של הטבלה עד שתוצאות ה-JSON ייטענו בפועל, אבל עדיין יכולים לאכלס את הטבלה בסוג כלשהו של נתוני placeholder כדי שהפריסה עצמה תהיה יציבה יחסית בזמן עיבוד ה-DOM.

זה הקוד ליצירת נתוני placeholder:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

נתוני ה-placeholder נוצרים באופן אקראי לפני שהם ממוינים. הפונקציה כוללת את התו "█" שחוזר על עצמו מספר אקראי של פעמים כדי ליצור ערכי placeholder חזותיים לטקסט והתפלגות אקראית של שלושת הערכים העיקריים. כמו כן, הוספתי כמה סגנונות כדי להפחית את הרוויה של כל הצבעים בטבלה כדי להבהיר שהנתונים עדיין לא טענו במלואו.

המראה של ה-placeholders שבהם אתה משתמש לא משנה את יציבות הפריסה. מטרת ה-placeholders היא להבטיח למשתמשים שהתוכן מופיע ושהדף לא מנותק.

כך נראים ה-placeholders בזמן הטעינה של נתוני JSON:

טבלת הנתונים עוברת עיבוד עם נתוני placeholder.
טבלת הנתונים עוברת עיבוד באמצעות נתוני placeholder.

הטיפול בבעיה של גופן באינטרנט הוא הרבה יותר פשוט. מכיוון שהאתר משתמש בגופנים של Google, אנחנו צריכים רק להעביר את המאפיין display=swap בבקשת ה-CSS. זה הכול. ה-Fonts API יוסיף את הסגנון font-display: swap להצהרת הגופן, ויאפשר לדפדפן לעבד טקסט בגופן חלופי באופן מיידי. אלה תגי העיצוב התואמים שכלולים בתיקון:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

אימות האופטימיזציות

אחרי הפעלה מחדש של הדף באמצעות WebPageTest, אנחנו יכולים ליצור השוואה לפני ואחרי, כדי להמחיש את ההבדל ולמדוד את הרמה החדשה של אי היציבות בפריסה:

רצועת תמונות של WebPageTest שמציגה את שני האתרים שנטענים זה לצד זה, עם אופטימיזציית פריסה ובלי אופטימיזציה.
רצועת תמונות של WebPageTest שמציגה את שני האתרים שנטענים זה לצד זה עם אופטימיזציה של הפריסה וגם בלי.
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

לפי המדד המותאם אישית, עדיין יש שינוי בפריסה במהירות של 3,071 אלפיות השנייה (בערך באותה תקופה כמו קודם), אבל חומרת השינוי הרבה קטנה יותר: 0.005%. אפשר להמשיך עם זה.

כמו כן, ניתן לראות ברצועת השקפים שהגופן <h1> חוזר מיד לגופן של המערכת, כדי שהמשתמשים יוכלו לקרוא אותו מהר יותר.

סיכום

סביר להניח שאתרים מורכבים יחוו הרבה יותר תנודות בפריסה מאשר בדוגמה הזו, אבל תהליך התיקון עדיין זהה: להוסיף ל-WebPageTest מדדי חוסר יציבות בפריסה, להצליב את התוצאות עם רצועת השקפים שנטענת כדי לזהות את הבעיה, וליישם תיקון באמצעות placeholders כדי לשריין את שטח המסך.

(עוד דבר) מדידה של חוסר יציבות בפריסה בקרב משתמשים אמיתיים

זה כיף להריץ WebPageTest בדף לפני ואחרי אופטימיזציה ולראות שיפור במדד, אבל מה שבאמת חשוב הוא שחוויית המשתמש משתפרת. לא זו הסיבה שאנחנו מנסים לשפר את האתר מלכתחילה?

אז מה יהיה נהדר אם נתחיל למדוד את חוויות אי היציבות של משתמשים אמיתיים בפריסה של משתמשים אמיתיים, יחד עם המדדים המסורתיים של ביצועי האינטרנט שלנו. זהו חלק חיוני בלולאת המשוב על אופטימיזציה, מכיוון שנתונים מהשטח מאפשרים לנו לדעת איפה הבעיות ואם התיקונים שלנו עזרו לנו לשפר את התוצאות.

בנוסף לאיסוף נתונים משלכם על חוסר יציבות בפריסה, כדאי לעיין בדוח חוויית המשתמש של Chrome, שכולל נתונים מצטברים בפריסת הפריסה, מחוויות משתמש אמיתיים במיליוני אתרים. אתם יכולים לבדוק את הביצועים שלכם (או של המתחרים שלכם), או להשתמש בו כדי לבדוק את המצב של חוסר היציבות בפריסה באינטרנט.