אין להילחם בסורק הטעינה מראש של הדפדפן

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

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

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

מה זה סורק טעינה מראש?

לכל דפדפן יש מנתח HTML ראשי שממיר תגי עיצוב גולמיים ומעבד אותם למודל אובייקט. התהליך הזה נמשך עד שהמנתח נתקל במשאב חוסם, כמו גיליון סגנונות שנטען עם רכיב <link>, או סקריפט שנטען עם רכיב <script> בלי מאפיין async או defer.

תרשים של מנתח HTML.
איור 1: דיאגרמה שמראה איך אפשר לחסום את מנתח ה-HTML הראשי של הדפדפן. במקרה הזה, המנתח נתקל ברכיב <link> של קובץ CSS חיצוני, שמונע מהדפדפן לנתח את שאר המסמך – או אפילו לעבד חלק ממנו – עד שה-CSS יורד ומנותח.

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

דף הבית של web.dev במצב לא מעוצב (מימין) ובמצב מעוצב (משמאל).
איור 2: דוגמה מדומה של FOUC. בצד ימין מוצג דף הבית של web.dev ללא סגנונות. בצד שמאל מוצג אותו דף עם סגנונות. מצב ללא סגנון יכול להתרחש במהירות אם הדפדפן לא חוסם את העיבוד בזמן שגיליון סגנונות יורד ומעובד.

הדפדפן גם חוסם את הניתוח והעיבוד של הדף כשהוא נתקל ברכיבי <script> בלי מאפיין defer או async.

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

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

תרשים של מנתח ה-HTML הראשי (משמאל) ושל סורק הטעינה מראש (מימין), שהוא מנתח ה-HTML המשני.
איור 3: דיאגרמה שממחישה איך סורק הטעינה מראש פועל במקביל למנתח ה-HTML הראשי כדי לטעון נכסים מראש. כאן, מנתח ה-HTML הראשי חסום כי הוא טוען ומעבד את ה-CSS לפני שהוא יכול להתחיל לעבד את תגי העיצוב של התמונה ברכיב <body>, אבל סורק הטעינה מראש יכול להסתכל קדימה בתגי העיצוב הגולמיים כדי למצוא את משאב התמונה הזה ולהתחיל לטעון אותו לפני שמנתח ה-HTML הראשי יבוטל.

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

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

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

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

תרשים המפל של רשת WebPageTest ממחיש עיכוב מלאכותי של 2 שניות שמוטל על גיליון הסגנונות.
איור 4: תרשים מפל מים של רשת ב-WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור מדומה לדור שלישי. למרות שגיליון הסגנונות מתעכב באופן מלאכותי באמצעות שרת proxy למשך שתי שניות לפני שהוא מתחיל להיטען, סורק הטעינה מראש מגלה את התמונה שנמצאת בהמשך המטען הייעודי (payload) של תגי העיצוב.

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

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

הוחדרו async סקריפטים

נניח שיש לכם קוד HTML ב-<head> שכולל קוד JavaScript מוטבע, כמו בדוגמה הבאה:

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

סקריפטים מוזרקים הם async כברירת מחדל, כך שכאשר הסקריפט הזה מוזרק, הוא יתנהג כאילו המאפיין async הוחל עליו. כלומר, הוא יפעל בהקדם האפשרי ולא יחסום את העיבוד. נשמע אופטימלי, נכון? עם זאת, אם מניחים שרכיב ה-<script> הזה מופיע אחרי רכיב <link> שטוען קובץ CSS חיצוני, התוצאה תהיה פחות טובה:

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

בואו ננתח את מה שקרה כאן:

  1. בשנייה ה-0, נשלחת בקשה למסמך הראשי.
  2. אחרי 1.4 שניות, מגיע הבייט הראשון של בקשת הניווט.
  3. אחרי 2.0 שניות, מתבצעת בקשה ל-CSS ולתמונה.
  4. מנתח הנתונים חסום בגלל טעינת גיליון הסגנונות, וקוד ה-JavaScript שמוטמע בקוד ומוסיף את הסקריפט של async מופיע אחרי גיליון הסגנונות הזה ב-2.6 שניות. לכן, הפונקציונליות שהסקריפט הזה מספק לא זמינה ברגע שהיא יכולה להיות זמינה.

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

אז מה קורה אם משתמשים בתג <script> רגיל עם המאפיין async במקום להוסיף את הסקריפט ל-DOM?

<script src="/yall.min.js" async></script>

זו התוצאה:

תרשים מפל של רשת WebPageTest שממחיש איך סורק הטעינה מראש של הדפדפן עדיין יכול לגלות סקריפט אסינכרוני שנטען באמצעות רכיב הסקריפט של HTML, למרות שמנתח ה-HTML הראשי של הדפדפן חסום בזמן ההורדה והעיבוד של גיליון סגנונות.
איור 6: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור מדומה לדור שלישי. הדף מכיל גיליון סגנונות אחד ורכיב async <script> אחד. סורק הטעינה מראש מגלה את הסקריפט במהלך שלב חסימת העיבוד, וטוען אותו במקביל ל-CSS.

יכול להיות שיהיה פיתוי להציע שאפשר לפתור את הבעיות האלה באמצעות rel=preload. זה בהחלט יעבוד, אבל יכולות להיות לזה כמה תופעות לוואי. אחרי הכול, למה להשתמש ב-rel=preload כדי לפתור בעיה שאפשר להימנע ממנה אם לא מוסיפים רכיב <script> ל-DOM?

תרשים Waterfall של WebPageTest שמראה איך משתמשים בהנחיית המשאב rel=preload כדי לקדם את הגילוי של סקריפט אסינכרוני שהוזרק – אם כי באופן שעשויות להיות לו תופעות לוואי לא מכוונות.
איור 7: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור 3G מדומה. הדף מכיל גיליון סגנונות אחד וסקריפט async מוזרק, אבל הסקריפט async נטען מראש כדי להבטיח שהוא יתגלה מוקדם יותר.

טעינה מראש "מתקנת" את הבעיה כאן, אבל היא מציגה בעיה חדשה: הסקריפט async בשני הדמו הראשונים – למרות שהוא נטען ב-<head> – נטען בעדיפות "נמוכה", ואילו גיליון הסגנונות נטען בעדיפות "הגבוהה ביותר". בהדגמה האחרונה, שבה הסקריפט async נטען מראש, גיליון הסגנונות עדיין נטען בעדיפות "הגבוהה ביותר", אבל העדיפות של הסקריפט קודמה ל"גבוהה".

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

התשובה כאן פשוטה: אם צריך סקריפט במהלך ההפעלה, אל תעקפו את סורק הטעינה מראש על ידי הזרקה שלו ל-DOM. כדאי להתנסות במיקום של הרכיב <script>, וגם במאפיינים כמו defer ו-async.

טעינה מדורגת באמצעות JavaScript

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

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

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

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

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

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

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

הפתרון הוא לשנות את תגי העיצוב של התמונה:

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

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

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

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

תמונות רקע ב-CSS

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

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

נניח שהמועמד ל-LCP של הדף הוא רכיב עם מאפיין CSS background-image. זה מה שקורה כשהמשאבים נטענים:

תרשים Waterfall של רשת WebPageTest שמתאר דף עם מועמד ל-LCP שנטען מ-CSS באמצעות המאפיין background-image. מכיוון שתמונת המועמד ל-LCP היא בסוג משאב שסורק הטעינה מראש של הדפדפן לא יכול לבדוק, טעינת המשאב מתעכבת עד להורדה ולעיבוד של ה-CSS, מה שמעכב את זמן הרינדור של המועמד ל-LCP.
איור 10: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור מדומה לדור שלישי. המועמד ל-LCP של הדף הוא רכיב עם מאפיין CSS background-image (שורה 3). התמונה שהיא מבקשת לא מתחילה להישלף עד שמנתח ה-CSS מוצא אותה.

במקרה כזה, סורק הטעינה מראש לא נכשל, אלא פשוט לא מעורב. עם זאת, אם מועמד ל-LCP בדף מגיע ממאפיין CSS של background-image, כדאי לטעון מראש את התמונה הזו:

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

ההנחיה rel=preload קטנה, אבל היא עוזרת לדפדפן לגלות את התמונה מהר יותר:

תרשים מפל של רשת WebPageTest שמציג תמונת רקע של CSS (שהיא המועמדת ל-LCP) שנטענת הרבה יותר מוקדם בגלל השימוש ברמז rel=preload. זמן ה-LCP משתפר בכ-250 אלפיות השנייה.
איור 11: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור מדומה לדור שלישי. המועמד ל-LCP של הדף הוא רכיב עם מאפיין CSS background-image (שורה 3). ההנחיה rel=preload עוזרת לדפדפן לגלות את התמונה כ-250 אלפיות השנייה מוקדם יותר מאשר בלי ההנחיה.

בעזרת ההנחיה rel=preload, המועמד ל-LCP מתגלה מוקדם יותר, וכך זמן ה-LCP מתקצר. הטיפ הזה עוזר לפתור את הבעיה, אבל יכול להיות שעדיף לבדוק אם התמונה שמועמדת ל-LCP חייבת להיטען מ-CSS. תג <img> מאפשר לכם לשלוט טוב יותר בטעינת תמונה שמתאימה לאזור התצוגה, וגם מאפשר לסורק הטעינה מראש לגלות אותה.

הטמעה של יותר מדי משאבים

הטמעה היא שיטה שבה ממקמים משאב בתוך ה-HTML. אפשר להטמיע גיליונות סגנונות ברכיבי <style>, סקריפטים ברכיבי <script> וכמעט כל משאב אחר באמצעות קידוד base64.

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

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

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

תרשים מפל של רשת WebPageTest של דף עם קובץ CSS חיצוני עם ארבעה גופנים שמפנים אליו. סורק הטעינה מראש מגלה את התמונה המועמדת ל-LCP במועד המתאים.
איור 12: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור מדומה של דור שלישי. המועמד ל-LCP של הדף הוא תמונה שנטענת מאלמנט <img>, אבל הוא מזוהה על ידי סורק הטעינה מראש כי ה-CSS והגופנים שנדרשים לדף נטענים במשאבים נפרדים, מה שלא מעכב את סורק הטעינה מראש מביצוע העבודה שלו.

מה קורה אם ה-CSS וגם כל הגופנים מוטמעים כמשאבי base64?

תרשים מפל מים של רשת WebPageTest של דף עם קובץ CSS חיצוני עם ארבעה גופנים שאליהם הוא מפנה. סורק הטעינה מראש מתעכב משמעותית בזיהוי תמונת ה-LCP .
איור 13: תרשים מפל של רשת WebPageTest של דף אינטרנט שפועל ב-Chrome במכשיר נייד דרך חיבור 3G מדומה. המועמד ל-LCP של הדף הוא תמונה שנטענה מרכיב <img>, אבל ההטמעה של ה-CSS וארבעת משאבי הגופנים שלו ב-`` מעכבת את סורק הטעינה מראש מלגלות את התמונה עד שהמשאבים האלה יורדו במלואם.

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

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

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

חשוב להיזהר כשמטמיעים דברים ב-HTML, במיוחד משאבים בקידוד base64. באופן כללי, לא מומלץ להשתמש בשיטה הזו, אלא אם מדובר במשאבים קטנים מאוד. השתדלו להשתמש כמה שפחות בהטמעה, כי שימוש מוגזם בהטמעה הוא משחק באש.

עיבוד תגי עיצוב באמצעות JavaScript בצד הלקוח

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

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

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

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

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

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

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

איך סורק הטעינה מראש יכול לעזור לכם

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

לסיכום, הנה הדברים החשובים שכדאי לזכור מהפוסט הזה:

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

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

משאבים