במודול הקודם, הסברנו את התיאוריה שמאחורי נתיב העיבוד הקריטי, ואיך משאבים שחוסמים את העיבוד וחוסמים את הניתוח יכולים לעכב את העיבוד הראשוני של הדף. אחרי שהבנתם את הרקע התיאורטי, אתם מוכנים ללמוד כמה טכניקות לאופטימיזציה של נתיב העיבוד הקריטי.
במהלך טעינת דף, יש הרבה משאבים שמפנים לקוד ה-HTML שלו, ומספקים לדף את המראה והפריסה שלו באמצעות CSS, וגם את האינטראקטיביות שלו באמצעות JavaScript. במודול הזה נסביר כמה מושגים חשובים שקשורים למשאבים האלה ולאופן שבו הם משפיעים על זמן הטעינה של דף.
עיבוד החסימה
כפי שצוין במודול הקודם, CSS הוא משאב שחוסם את העיבוד, כי הוא מונע מהדפדפן לעבד תוכן כלשהו עד שנוצר מודל אובייקט CSS (CSSOM). הדפדפן חוסם את העיבוד כדי למנוע הבזק של תוכן לא מעוצב (FOUC), שפוגע בחוויית המשתמש.
בסרטון הקודם, יש FOUC קצר שבו אפשר לראות את הדף ללא עיצוב. לאחר מכן, כל הסגנונות מוחלים ברגע שקובץ ה-CSS של הדף סיים להיטען מהרשת, והגרסה של הדף ללא סגנון מוחלפת מיד בגרסה עם הסגנון.
באופן כללי, FOUC הוא משהו שלא רואים בדרך כלל, אבל חשוב להבין את המושג כדי לדעת למה הדפדפן חוסם את העיבוד של הדף עד שקובץ ה-CSS מורד ומוחל על הדף. חסימת עיבוד (Render blocking) היא לא בהכרח דבר רע, אבל כדאי לצמצם את משך הזמן שלה על ידי אופטימיזציה של ה-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, ולא ניתן לגלות אותם באמצעות סורק הטעינה מראש.
- הצהרות של שירות CSS
@import
.
כל דפוסי טעינת המשאבים האלה הם משאבים שמתגלים בשלב מאוחר, ולכן לא נהנים מסורק הטעינה מראש. כדאי להימנע מהם ככל האפשר. אם אי אפשר להימנע מדפוסים כאלה, אפשר להשתמש ברמז 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 שלא בשימוש
לפני עיבוד התוכן, הדפדפן צריך להוריד ולנתח את כל גיליונות הסגנונות. הזמן שנדרש להשלמת הניתוח כולל גם סגנונות שלא נעשה בהם שימוש בדף הנוכחי. אם אתם משתמשים בחבילת קבצים שמשלבת את כל משאבי ה-CSS בקובץ אחד, סביר להניח שהמשתמשים שלכם מורידים יותר CSS ממה שנדרש כדי לעבד את הדף הנוכחי.
כדי לגלות תוכן CSS שלא נמצא בשימוש בדף הנוכחי, משתמשים בכלי Coverage ב-Chrome DevTools.

להסרת רכיבי CSS שלא בשימוש יש השפעה כפולה: בנוסף לקיצור זמן ההורדה, אתם מבצעים אופטימיזציה של בניית עץ העיבוד, כי הדפדפן צריך לעבד פחות כללי CSS.
הימנעות מהצהרות CSS @import
למרות שזה אולי נראה נוח, כדאי להימנע מהצהרות @import
ב-CSS:
/* Don't do this: */
@import url('style.css');
בדומה לאופן הפעולה של הרכיב <link>
ב-HTML, ההצהרה @import
ב-CSS מאפשרת לייבא משאב CSS חיצוני מתוך גיליון סגנונות. ההבדל העיקרי בין שתי הגישות האלה הוא שהרכיב <link>
של HTML הוא חלק מתגובת ה-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 המקורי. התהליך הזה נקרא לפעמים uglification. כדי לראות את ההבדל, ניקח את קוד המקור הבא של 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);
}
כשמבצעים uglification בקוד המקור של 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 של אתר מספק.
אם אתם משתמשים בכלי לאיגוד קבצים כדי לעבד את קוד המקור של האתר, לעיתים קרובות תהליך ה-uglification מתבצע באופן אוטומטי בגרסאות שמיועדות לייצור. גם כלי Uglifiers – כמו Terser, למשל – ניתנים להגדרה במידה רבה, כך שאפשר לשנות את רמת האגרסיביות של אלגוריתם ה-Uglification כדי להשיג חיסכון מקסימלי. עם זאת, הגדרות ברירת המחדל של כל כלי להסרת תכונות מיותרות בדרך כלל מספיקות כדי להשיג את האיזון הנכון בין גודל הפלט לבין שימור היכולות.
הדגמות של JavaScript
בוחנים את הידע
מה הדרך הכי טובה לטעון כמה קובצי CSS בדפדפן?
<link>
.@import
של CSS.מה עושה סורק הטעינה מראש בדפדפן?
<link rel="preload">
במשאב HTML.
למה הדפדפן חוסם באופן זמני את הניתוח של HTML כברירת מחדל כשמורידים משאבי JavaScript?
הנושא הבא: עזרה לדפדפן באמצעות רמזים למשאבים
עכשיו, אחרי שהבנתם איך משאבים שנטענים ברכיב <head>
יכולים להשפיע על הטעינה הראשונית של הדף ועל מדדים שונים, הגיע הזמן להמשיך. במודול הבא, נסביר על רמזים למשאבים ואיך הם יכולים לספק לדפדפן רמזים חשובים להתחלת טעינת משאבים ולפתיחת חיבורים לשרתים חוצי-מקורות מוקדם יותר ממה שהדפדפן היה עושה בלעדיהם.