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

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

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

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

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

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

כדי לעזור לחזות FID במעבדה, ממליצים על Total חסימה זמן (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 אחרי אופטימיזציה של סקריפט מאינטראקציה ישירה.

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

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

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

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

שימוש ב-Web Worker

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

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

  • Comlink: ספרייה מסייעת שמפשטת את postMessage וקל יותר להשתמש בו
  • סביבת עבודה: יצואנים של משתמשי אינטרנט לשימוש כללי
  • 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 כחבילה של מודולים, כדאי לנצל את והתמיכה שלהם בייבוא דינמי.
  • מסגרות בצד הלקוח, כמו תגובה, Angular, וגם ציון של Vue הפשטות שנועדו להקל על טעינה מדורגת ברמת הרכיב.

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

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

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

מזעור ה-polyfills שלא נמצאים בשימוש

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

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

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

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

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

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

כלים למפתחים

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

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