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

בקודלאב הזה משפרים את הביצועים של דף האינטרנט הבא באמצעות טעינת נתונים מראש (preload) של כמה משאבים ושליפה מראש (prefetch) שלהם:

צילום מסך של האפליקציה

מדידה

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

  • כדי לראות תצוגה מקדימה של האתר, לוחצים על View App (הצגת האפליקציה) ואז על Fullscreen מסך מלא (מסך מלא).

מריצים את ביקורת הביצועים של Lighthouse (Lighthouse > Options > Performance) בגרסה הפעילה של Glitch (ראו גם זיהוי הזדמנויות לשיפור הביצועים באמצעות Lighthouse).

מערכת Lighthouse מציגה את הביקורת שנכשלה הבאה לגבי משאב שאוחזר באיחור:

Lighthouse: ביקורת של בקשות מפתח לטעינה מראש
  • מקישים על 'Control+Shift+J' (או על 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
  • לוחצים על הכרטיסייה רשתות.
חלונית 'רשת' עם משאב שזוהה מאוחר

קובץ main.css לא מאוחזר על ידי אלמנט קישור (<link>) שמופיע במסמך ה-HTML, אלא על ידי קובץ JavaScript נפרד, fetch-css.js, שמצרף את אלמנט הקישור ל-DOM אחרי האירוע window.onLoad. כלומר, האחזור של הקובץ מתבצע רק אחרי שהדפדפן מסיים לנתח ולבצע את קובץ ה-JS. באופן דומה, אחזור של פונט אינטרנט (K2D.woff2) שצוין ב-main.css מתבצע רק אחרי שההורדה של קובץ ה-CSS מסתיימת.

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

├─┬ / (initial HTML file)
  └── fetch-css.js
    └── main.css
      └── K2D.woff2

מכיוון שקובץ ה-CSS נמצא ברמה השלישית של שרשרת הבקשות, מערכת Lighthouse זיהתה אותו כמשאב שהתגלה מאוחר.

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

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

מוסיפים תג טעינה מראש לאפליקציה הזו:

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
</head>

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

טוענים מחדש את האפליקציה ומעיינים בחלונית Network (רשת) בכלי הפיתוח.

חלונית &#39;רשת&#39; עם משאב טעון מראש

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

אם לא משתמשים בה בצורה נכונה, טעינת הנתונים מראש עלולה להזיק לביצועים על ידי שליחת בקשות מיותרות למשאבים שלא נמצאים בשימוש. באפליקציה הזו, details.css הוא קובץ CSS אחר שנמצא ברמה הבסיסית (root) של הפרויקט, אבל משמש לקובץ /details route נפרד. כדי להראות דוגמה לאופן שבו אפשר להשתמש בצורה שגויה בטעינה מראש, צריך להוסיף גם רמז לטעינה מראש בשביל המשאב הזה.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

טוענים מחדש את האפליקציה ומעיינים בחלונית Network. נשלחת בקשה לאחזור details.css, למרות שדף האינטרנט לא משתמש בו.

חלונית &#39;רשת&#39; עם טעינה מראש מיותרת

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

אזהרה על טעינה מראש במסוף

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

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

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

אחזור מראש של משאבים עתידיים

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

באתר הזה, לחיצה על התמונה תעביר אתכם לנתיב details/ נפרד.

פרטי המסלול

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

<head>
  <!-- ... -->
  <link rel="prefetch" href="details.css">
</head>

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

השבתת המטמון בכלי הפיתוח ל-Chrome

טענו מחדש את האפליקציה שימו לב שהבקשה ל-details.css נשלחת בעדיפות נמוכה מאוד אחרי שאחזור כל שאר הקבצים.

חלונית רשת עם משאב שנשלף מראש

כשכלי הפיתוח פתוחים, לוחצים על התמונה באתר כדי לנווט לדף details. מאחר שרכיב קישור משמש ב-details.html כדי לאחזר את details.css, נשלחת בקשה למשאב כצפוי.

בקשות רשת בדף הפרטים

לוחצים על בקשת הרשת details.css ב-DevTools כדי להציג את הפרטים שלה. תוכלו לראות שהקובץ מאוחזר ממטמון הדיסק של הדפדפן.

בקשת פרטים שאוחזרה ממטמון האחסון

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

טעינה מראש ושליפה מראש (prefetch) באמצעות webpack

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

אפליקציית Magic Sorter שממחישה פיצול קוד

ניתן לגשת אל התקלה של האפליקציה הזו כאן.

קטע הקוד הבא, שנמצא ב-src/index.js,, אחראי לייבוא דינמי של ה-method כשלוחצים על הלחצן.

form.addEventListener("submit", e => {
  e.preventDefault()
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

פיצול חבילה משפרת את זמני הטעינה של הדפים על ידי צמצום הגודל הראשוני שלה. גרסה 4.6.0 של webpack מספקת תמיכה טעינה מראש של קטעי קוד (chunks) שיובאו באופן דינמי, או טעינה מראש של קטעי קוד שמיועדים לטעינה מראש. לדוגמה, באפליקציה הזו אפשר לאחזר מראש את השיטה lodash בזמן שהדפדפן לא פעיל. כך, כשהמשתמש לוחץ על הלחצן, אין עיכוב באחזור המשאב.

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

form.addEventListener("submit", e => {
  e.preventDefault()
  import(/* webpackPrefetch: true */ 'lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

אחרי שהאפליקציה נטענת מחדש, ה-webpack מחדיר תג שליפה מראש של המשאב לראש המסמך. אפשר לראות את זה בחלונית Elements ב-DevTools.

חלונית רכיבים עם תג של אחסון מקדים

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

חלונית רשת עם בקשה שנשלפה מראש

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

import(/* webpackPreload: true */ 'module')

סיכום

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

לסיכום:

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

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

במאמרים הבאים תוכלו לקרוא מידע נוסף על היבטים ספציפיים של ההשפעה של טעינה מראש ושליפה מראש (prefetch) על דף האינטרנט: