אופטימיזציה של השהיית הקלט הראשון

איך להגיב מהר יותר לאינטראקציות של משתמשים.

אדי אוסמאני
אדי אוסמאני

לחצתי אבל לא קרה כלום! למה אין לי אפשרות לבצע פעולות בדף הזה? 😢

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

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

ערכי ה-סמך הטובים הם 2.5 שניות, הערכים הנמוכים הם יותר מ-4.0 שניות, ובכל דבר שביניהם נדרש שיפור

כדי לחזות את מקרים של FID במעבדה, מומלץ להשתמש באפשרות זמן חסימה כולל (TBT). הם מודדים דברים שונים, אבל שיפורים ב-TBT בדרך כלל תואמים לשיפורים ב-FID.

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

ביצוע כבד של JavaScript

הדפדפן לא יכול להגיב לרוב הקלט של המשתמשים כשהוא מריץ JavaScript ב-thread הראשי. במילים אחרות, הדפדפן לא יכול להגיב לאינטראקציות של משתמשים כשה-thread הראשי לא פנוי. כדי לשפר את המצב:

פיצול משימות ארוכות

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

משימות ארוכות הן תקופות הפעלה של JavaScript שבהן משתמשים עשויים לראות שממשק המשתמש שלכם לא מגיב. אפשר לאפיין כל קטע קוד שחוסם את ה-thread הראשי למשך 50 אלפיות השנייה או יותר כ'משימה ארוכה'. משימות ארוכות הן סימן לריבוי פוטנציאלי של JavaScript (טעינה וביצוע של יותר פעולות שהמשתמשים עשויים להזדקק להן כרגע). פיצול משימות ארוכות יכול להפחית את עיכוב הקלט באתר.

משימות ארוכות בכלי הפיתוח ל-Chrome
כלי הפיתוח ל-Chrome מציג את המשימות הארוכות בחלונית הביצועים

השיטות המומלצות כמו פיצול קוד וחלוקה של המשימות הארוכות ישתפרו משמעותית ב-FID. TBT הוא לא מדד של השדה, אבל הוא שימושי לבדיקת ההתקדמות כדי לשפר בסופו של דבר את ה-Time To Interactive (TTI) ואת FID.

אופטימיזציה של הדף לשיפור המוּכנוּת לאינטראקציה

יש כמה סיבות נפוצות לציוני FID ו-TBT נמוכים באפליקציות אינטרנט שמסתמכות במידה רבה על JavaScript:

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

  • ריבוי גודל של JavaScript, זמני ביצוע כבדים וצ'אט לא יעיל עלולים להאט את מהירות התגובה של הדף לקלט של משתמשים ולהשפיע על FID, TBT ו-TTI. טעינה הדרגתית של קוד ותכונות יכולה לעזור לכם לפזר את האימון הזה ולשפר את המוכנות לאינטראקציה.
  • אפליקציות שמעובדות בצד השרת עשויות להיראות כאילו הן נצבעות על המסך במהירות פיקסלים, אבל חשוב לשים לב שאינטראקציות של משתמשים חסומות על ידי הפעלות גדולות של סקריפטים (למשל, הזנה מחדש של המים כדי להעביר פונקציות event listener). הפעולה הזו יכולה להימשך כמה מאות אלפיות השנייה, לפעמים אפילו שניות, אם משתמשים בפיצול קוד מבוסס-נתיב. כדאי לשנות את הלוגיקה יותר בצד השרת או ליצור יותר תוכן באופן סטטי במהלך ה-build.

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

שיפורים בציון TBT ב-Lighthouse אחרי אופטימיזציה של הסקריפט מאינטראקציה ישירה.

שליפת נתונים יכולה להשפיע על היבטים רבים של מוכנות לאינטראקציה

  • המתנה במפל של אחזורים מדורגים (למשל, JavaScript ואחזורי נתונים של רכיבים) יכולה להשפיע על זמן האחזור של האינטראקציות. המטרה היא לצמצם את ההסתמכות על אחזור נתונים מדורגים.
  • מאגרי נתונים מוטבעים גדולים יכולים לעכב את זמן ניתוח ה-HTML ולהשפיע גם על מדדי צבע וגם על מדדי אינטראקציה. המטרה היא לצמצם את כמות הנתונים שצריך לעבור לאחר העיבוד בצד הלקוח.

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

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

שימוש ב-Web Worker

אחד הגורמים העיקריים לעיכוב בקלט הוא thread ראשי חסום. עובדי אינטרנט מאפשרים להריץ JavaScript בשרשור ברקע. העברה של פעולות שלא קשורות ל-UI ל-thread נפרד של worker יכולה לקצר את זמן החסימה של ה-thread הראשי וכתוצאה מכך לשפר את ה-FID.

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

  • Comlink: ספריית עזרה שמפשטת את postMessage ומקלה על השימוש
  • Workway: יצואן Web Worker לשימוש כללי
  • Workerize: העברת מודול ל-Web worker

קיצור זמן הביצוע של JavaScript

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

כדי להפחית את כמות ה-JavaScript שמופעלת בדף:

  • דחייה של קובצי JavaScript שאינם בשימוש
  • מזעור polyfills שאינם בשימוש

דחייה של קובצי JavaScript שאינם בשימוש

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

בכרטיסייה כיסוי בכלי הפיתוח ל-Chrome אפשר לראות באיזו תדירות לא נעשה שימוש ב-JavaScript בדף האינטרנט.

הכרטיסייה 'כיסוי'.

כדי לצמצם את השימוש ב-JavaScript שאינו בשימוש:

  • פיצול החבילה למספר מקטעים
  • דחיית JavaScript שאינו קריטי, כולל סקריפטים של צד שלישי, באמצעות async או defer

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

import('module.js').then((module) => {
  // Do something with the module.
});

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

מלבד תמיכה כללית בדפדפן, אפשר להשתמש בתחביר של ייבוא דינמי במגוון מערכות build.

  • אם אתם משתמשים ב-webpack, ב-Rollup או ב-Parcel בתור חבילת מודולים, תוכלו להיעזר בתמיכה שלהם בייבוא הדינמי.
  • מסגרות בצד הלקוח, כמו React, Angular ו-Vue, מספקות הפשטות כדי שיהיה קל יותר לבצע טעינה מדורגת ברמת הרכיב.

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

<script defer src="…"></script>
<script async src="…"></script>

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

מזעור polyfills שאינם בשימוש

אם כותבים את הקוד באמצעות תחביר JavaScript מודרני, ומתייחס לממשקי API מודרניים של דפדפנים, צריך להמיר אותו ולכלול שדות polyfills כדי שהוא יפעל בדפדפנים ישנים יותר.

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

כדי לבצע אופטימיזציה של השימוש ב-polyfill באתר שלכם:

  • אם אתם משתמשים ב-Babel כממיר, השתמשו ב-@babel/preset-env כדי לכלול רק את ה-polyfills שאתם צריכים לדפדפנים שאליהם אתם מתכננים לטרגט. ב-Babel 7.9, מפעילים את האפשרות bugfixes כדי לצמצם עוד יותר את מילויי ה-Polyfill שלא נחוצים
  • שימוש בתבנית המודול/nomodule כדי להעביר שתי חבילות נפרדות (אפשר להשתמש ב-@babel/preset-env גם דרך target.esmodules)

    <script type="module" src="modern.js"></script>
    <script nomodule src="legacy.js" defer></script>
    

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

כלים למפתחים

יש מספר כלים זמינים למדידה ולניפוי באגים של FID:

  • בגרסה 6.0 של Lighthouse אין תמיכה ב-FID, כי זהו מדד של שדות. עם זאת, אפשר להשתמש ב-Total block Time (TBT) בתור שרת proxy. גם פעולות אופטימיזציה שמשפרות את TBT אמורות לשפר את ה-FID בשדה.

    Lighthouse 6.0.

  • דוח חוויית המשתמש ב-Chrome מספק ערכי FID אמיתיים שנצברים ברמת המקור

תודה על הביקורות שנכתבו על ידי פיליפ וולטון, קייס באסק, אילייה גריגוריק ואנני סאליבן.