במודול הקודם, חקרנו תיאוריה מסוימת שמאחורי נתיב העיבוד הקריטי, והאופן שבו משאבים שחוסמים עיבוד וחסימת מנתח יכולים לעכב את העיבוד הראשוני של דף. עכשיו, אחרי שהבנתם חלק מהתיאוריה שעומדת מאחורי, אתם מוכנים ללמוד כמה טכניקות לאופטימיזציה של נתיב העיבוד הקריטי.
במהלך טעינת הדף, הפניות למשאבים רבים ב-HTML של הדף מספקים את המראה והפריסה שלו באמצעות CSS, וכן את האינטראקטיביות באמצעות JavaScript. במודול הזה נסביר על כמה מושגים חשובים שקשורים למשאבים האלה והאופן שבו הם משפיעים על זמן הטעינה של דף.
עיבוד החסימה
כפי שצוין במודול הקודם, CSS הוא משאב לחסימת עיבוד, מאחר שהוא מונע מהדפדפן לעבד תוכן עד לבנייה של מודל האובייקטים של CSS (CSSOM). הדפדפן חוסם את הרינדור כדי למנוע Flash של תוכן ללא סגנון (FOUC), שהוא מצב לא רצוי מבחינת חוויית המשתמש.
בסרטון הקודם יש FOUC קצר שבו אפשר לראות את הדף ללא סגנון. לאחר מכן, כל הסגנונות מוחלים לאחר סיום הטעינה של ה-CSS של הדף מהרשת, והגרסה ללא עיצוב של הדף מוחלפת מיד בגרסה המעוצבת.
באופן כללי, שגיאת FOUC היא בעיה שלרוב אי אפשר לראות, אבל חשוב להבין את המושג כדי שתדעו למה הדפדפן חוסם את עיבוד הדף עד שמורידים את ה-CSS ומחילים אותו על הדף. חסימת עיבוד היא לא בהכרח פעולה בלתי רצויה, אבל כדאי לצמצם את משך הזמן על ידי שמירה על רמת האופטימיזציה של ה-CSS.
חסימת מנתח
משאב חסימת מנתח מפריע למנתח ה-HTML, למשל רכיב <script>
בלי המאפיינים async
או defer
. כשהמנתח נתקל ברכיב <script>
, הדפדפן צריך להעריך ולהפעיל את הסקריפט לפני שימשיך בניתוח שאר ה-HTML. הסיבה לכך היא שסקריפטים עשויים לשנות את ה-DOM או לגשת אליו במהלך הזמן שהוא עדיין בבנייה.
<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>
כשמשתמשים בקובצי JavaScript חיצוניים (בלי async
או defer
), המנתח חסום מרגע הגילוי של הקובץ ועד להורדה, לניתוח ולהפעלה. כשמשתמשים ב-JavaScript מוטבע, המנתח חסום באופן דומה עד שהסקריפט המוטבע מנותח ויופעל.
סורק הטעינה מראש
סורק הטעינה מראש הוא הכלי לאופטימיזציה של הדפדפן, בצורת מנתח HTML משני שסורק את התגובה הגולמית של ה-HTML כדי למצוא משאבים ולאחזר משאבים לפני שמנתח ה-HTML הראשי מגלה אותם. לדוגמה, סורק הטעינה מראש יאפשר לדפדפן להתחיל להוריד משאב שצוין ברכיב <img>
, גם אם מנתח ה-HTML חסום
בזמן אחזור ועיבוד של משאבים כמו CSS ו-JavaScript.
כדי להשתמש בסורק הטעינה מראש, צריך לכלול משאבים קריטיים בתגי העיצוב של HTML שנשלחים על ידי השרת. הדפוסים הבאים לטעינת משאבים לא גלויים לסורק הטעינה מראש:
- תמונות שנטענות על ידי שירות CSS באמצעות הנכס
background-image
. ההפניות האלה לתמונות נמצאות ב-CSS וסורק הטעינה מראש לא יכול לגלות אותן. - סקריפטים שנטענים באופן דינמי בצורת תגי עיצוב של רכיב
<script>
, שהוחדרו ל-DOM באמצעות JavaScript או מודולים שנטענו באמצעות Dynamicimport()
. - קוד HTML שעבר עיבוד בלקוח באמצעות JavaScript. תגי העיצוב האלה נמצאים במחרוזות במשאבי JavaScript, והסורק של הטעינה מראש לא יכול לראות אותם.
- הצהרות
@import
של שירות CSS.
הדפוסים האלה לטעינת משאבים הם משאבים שהתגלו בשלב מאוחר יותר, ולכן סורק הטעינה מראש לא שימושי בהם. מומלץ להימנע מהם ככל האפשר. אבל אם לא ניתן להימנע מתבניות כאלה, אפשר להשתמש ברמז preload
כדי למנוע עיכובים בגילוי המשאבים.
CSS
ה-CSS קובע את התצוגה והפריסה של דף. כפי שתואר קודם, CSS הוא משאב שחוסם עיבוד, ולכן לאופטימיזציה של ה-CSS יכולה להיות השפעה משמעותית על זמן הטעינה הכולל של הדף.
הקטנה
הקטנת קובצי CSS מפחיתה את גודל הקובץ של משאב CSS, כך שההורדה שלהם מהירה יותר. הפעולה הזו מתבצעת בעיקר על ידי הסרת תוכן מקובץ CSS מקורי כמו רווחים ותווים נסתרים אחרים, ופלט התוצאה לקובץ שעבר אופטימיזציה:
/* Unminified CSS: */
/* Heading 1 */
h1 {
font-size: 2em;
color: #000000;
}
/* Heading 2 */
h2 {
font-size: 1.5em;
color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}
בצורתו הבסיסית ביותר, הקטנת CSS היא אופטימיזציה יעילה שעשויה לשפר את ה-FCP של האתר, ובמקרים מסוימים אפילו את ה-LCP. כלים כמו bundlers (חבילות) יכולים לבצע את האופטימיזציה הזו באופן אוטומטי בגרסאות build של ייצור.
יש להסיר שירות CSS שאינו בשימוש
לפני עיבוד התוכן, הדפדפן צריך להוריד ולנתח את כל גיליונות הסגנונות. הזמן הנדרש להשלמת הניתוח כולל גם סגנונות שלא נמצאים בשימוש בדף הנוכחי. אם אתם משתמשים ב-bundler שמשלב את כל משאבי ה-CSS בקובץ אחד, סביר להניח שהמשתמשים שלכם מורידים יותר CSS מהנדרש כדי לעבד את הדף הנוכחי.
כדי לאתר קובץ CSS שלא נמצא בשימוש בדף הנוכחי, משתמשים בכלי הכיסוי בכלי הפיתוח ל-Chrome.
להסרה של CSS שאינו בשימוש יש השפעה כפולה: בנוסף לקיצור זמן ההורדה, אתם מבצעים אופטימיזציה של בניית עץ עיבוד, כי הדפדפן צריך לעבד פחות כללי CSS.
הימנעות מהצהרות @import
של שירות CSS
אולי זה נראה לך נוח, אבל כדאי להימנע מהצהרות @import
ב-CSS:
/* Don't do this: */
@import url('style.css');
בדומה לאופן שבו הרכיב <link>
פועל ב-HTML, ההצהרה @import
ב-CSS מאפשרת לייבא משאב CSS חיצוני מתוך גיליון סגנונות. ההבדל העיקרי בין שתי הגישות הוא שרכיב ה-HTML <link>
הוא חלק מתגובת ה-HTML, ולכן התגלה הרבה יותר מהר מקובץ CSS שהורד באמצעות הצהרת @import
.
הסיבה לכך היא שכדי שהצהרת @import
תיחשף, יש להוריד תחילה את קובץ ה-CSS שמכיל אותה. התוצאה היא שרשרת בקשות, שבמקרה של CSS, מעכבת את משך העיבוד הראשוני של הדף. חיסרון נוסף הוא שגיליונות סגנונות שנטענים באמצעות הצהרת @import
לא ניתנים לגילוי על ידי סורק הטעינה מראש, ולכן הם הופכים למשאבים שחוסמים עיבוד בשלב מאוחר יותר.
<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">
ברוב המקרים, אפשר להחליף את @import
באמצעות רכיב <link rel="stylesheet">
. רכיבי <link>
מאפשרים הורדה של גיליונות סגנונות בו-זמנית ומפחיתים את זמן הטעינה הכולל, בניגוד להצהרות @import
, שמאפשרות הורדה של גיליונות סגנונות ברציפות.
הטמעת CSS חיוני
משך הזמן שחולף עד להורדת קובצי CSS עלול להגדיל את ערך ה-FCP של דף. הטבעת סגנונות קריטיים במסמך <head>
מבטלת את בקשת הרשת למשאב CSS. כשהשימוש נכון, היא יכולה לקצר את זמני הטעינה הראשוניים כשאין הגדרות במטמון של הדפדפן של המשתמש. ניתן לטעון את ה-CSS הנותר באופן אסינכרוני או לצרף אותו בסוף הרכיב <body>
.
<head>
<title>Page Title</title>
<!-- ... -->
<style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
<!-- Other page markup... -->
<link rel="stylesheet" href="non-critical.css">
</body>
מעבר לכך, הטבעת כמות גדולה של CSS מוסיפה בייטים לתגובת ה-HTML הראשונית. במקרים רבים אי אפשר לשמור משאבי HTML למשך זמן ארוך מאוד, או בכלל, לכן ה-CSS המוטבע לא נשמר במטמון של הדפים הבאים שעשויים להשתמש באותו CSS בגיליונות סגנונות חיצוניים. מומלץ לבדוק ולמדוד את הביצועים של הדף כדי לוודא שכל המאמץ שווים את המאמץ.
הדגמות של שירות CSS
JavaScript
JavaScript מביא את רוב האינטראקטיביות באינטרנט, אבל הוא כרוך בעלות מסוימת. שליחת יותר מדי JavaScript עלולה להאט את התגובה של דף האינטרנט במהלך טעינת הדף, והיא עלולה אפילו לגרום לבעיות בתגובתיות ולהאט את האינטראקציות – ושתי הבעיות עלולות להיות מתסכלות למשתמשים.
JavaScript החוסם עיבוד
כשטוענים רכיבי <script>
ללא המאפיינים defer
או async
,
הדפדפן חוסם את הניתוח והעיבוד עד שהסקריפט יורד, ינותח
וההרצה שלו. באופן דומה, סקריפטים מוטבעים חוסמים את המנתח עד שהסקריפט מנותח ויופעל.
async
לעומת defer
async
ו-defer
מאפשרים לסקריפטים חיצוניים להיטען בלי לחסום את מנתח ה-HTML, ואילו סקריפטים (כולל סקריפטים מוטבעים) עם type="module"
נדחים באופן אוטומטי. עם זאת, יש כמה הבדלים בין async
לבין defer
שחשוב להבין.
סקריפטים שנטענים עם async
מנותחים ומופעלים מיד אחרי ההורדה, וסקריפטים שנטענים באמצעות defer
מבוצעים כשניתוח מסמך ה-HTML מסתיים. הפעולה הזו מתרחשת באותו הזמן כמו אירוע DOMContentLoaded
בדפדפן.
בנוסף, סקריפטים של async
עשויים לפעול באופן לא תקין, ו-defer
סקריפטים עשויים לפעול לפי הסדר שבו הם מופיעים בתגי העיצוב.
רינדור בצד הלקוח
באופן כללי, כדאי להימנע משימוש ב-JavaScript כדי לעבד תוכן קריטי או את הרכיב LCP של דף מסוים. התהליך הזה נקרא רינדור בצד הלקוח, והוא טכניקה שנעשה בה שימוש נרחב באפליקציות בדף יחיד (SPA).
תגי עיצוב שמעובדים על ידי JavaScript עוקפים את סורק הטעינה מראש, כי המשאבים שכלולים בתגי העיצוב שעובדו על ידי הלקוח לא ניתנים לגילוי. זה עלול לעכב את ההורדה של משאבים חיוניים, כמו תמונת LCP. הדפדפן מתחיל להוריד את תמונת ה-LCP רק אחרי שהסקריפט מבוצע, ומוסיף את הרכיב ל-DOM. בתורו, ניתן להפעיל את הסקריפט רק לאחר הגילוי, ההורדה והניתוח. מצב כזה נקרא שרשרת בקשות קריטית וצריך להימנע מכך.
בנוסף, יש סבירות גבוהה יותר שתגי עיצוב באמצעות JavaScript ייצרו משימות ארוכות מאשר תגי עיצוב שהורדו מהשרת בתגובה לבקשת ניווט. שימוש נרחב ברינדור HTML בצד הלקוח עלול להשפיע לרעה על זמן האחזור של אינטראקציות. זה נכון במיוחד במקרים שבהם ה-DOM של הדף גדול מאוד, מה שמוביל לפעולת רינדור משמעותית כש-JavaScript משנה את ה-DOM.
הקטנה
בדומה ל-CSS, הקטנת JavaScript מפחיתה את גודל הקובץ של משאב סקריפט. כך אפשר להאיץ את ההורדות ולאפשר לדפדפן לעבור מהר יותר לתהליך הניתוח וההידור של JavaScript.
בנוסף, הקטנה של JavaScript היא שלב נוסף יותר מהקטנת נכסים אחרים כמו CSS. כשמצמצמים את JavaScript, הוא לא רק נמחק מדברים כמו רווחים, כרטיסיות ותגובות, אלא גם הסמלים במקור ה-JavaScript מקוצרים. התהליך הזה נקרא לפעמים התאמה. כדי לראות את ההבדלים, השתמשו בקוד המקור הבא של JavaScript:
// Unuglified JavaScript source code:
export function injectScript () {
const scriptElement = document.createElement('script');
scriptElement.src = '/js/scripts.js';
scriptElement.type = 'module';
document.body.appendChild(scriptElement);
}
כאשר קוד המקור של JavaScript הקודם הוטמע, התוצאה עשויה להיראות בערך כמו קטע הקוד הבא:
// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}
בקטע הקוד הקודם, ניתן לראות שהמשתנה הקריא (לבני אדם) scriptElement
במקור קוצר ל-t
. כשמחילים אותו על מספר גדול של סקריפטים, החיסכון יכול להיות משמעותי מאוד, מבלי להשפיע על התכונות שמספק ה-JavaScript באתר ליצירת סקריפטים.
אם אתם משתמשים ב-bundler כדי לעבד את קוד המקור של האתר שלכם, פעולת ההחלקה מבוצעת בדרך כלל באופן אוטומטי לגרסאות build ייצור. כמו Terser, למשל, יש גם אפשרויות הגדרה גבוהות, וכך אפשר לשנות את מידת האגרסיביות של אלגוריתם ההדגשה כדי לחסוך כמה שיותר. עם זאת, ערכי ברירת המחדל של כל כלי ההחרגה בדרך כלל מספיקים כדי למצוא את האיזון הנכון בין גודל הפלט לבין שימור היכולות.
הדגמות JavaScript
בוחנים את הידע
מהי הדרך הטובה ביותר לטעון מספר קובצי CSS בדפדפן?
@import
של שירות ה-CSS.<link>
.מה עושה סורק הטעינה מראש של הדפדפן?
<link rel="preload">
במשאב HTML.
למה הדפדפן חוסם באופן זמני את הניתוח של HTML כברירת מחדל כשמורידים משאבי JavaScript?
השלב הבא: סיוע לדפדפן עם רמזים למשאבים
עכשיו, אחרי שהבנתם איך המשאבים שנטענים ברכיב <head>
יכולים להשפיע על הטעינה הראשונית של הדף ועל מדדים שונים, הגיע הזמן להתקדם. במודול הבא נציג את הרמזים למשאבים ונסביר איך הם יכולים לספק רמזים חשובים לדפדפן, כדי להתחיל לטעון משאבים ולפתוח חיבורים לשרתים עם מקורות מידע שונים מהר יותר מאשר בלעדיהם הדפדפן.