אופטימיזציה של קוד JavaScript של צד שלישי

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

  • דחיית טעינה של סקריפט

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

  • קישור מראש למקורות נדרשים

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

  • הטמעת סרטון

  • ספריית ויזואליזציה של נתונים לעיבוד תרשים קו

  • ווידג'ט לשיתוף במדיה חברתית

צילום מסך של הדף עם הדגשה של משאבים של צד שלישי.
משאבים של צד שלישי באפליקציית הדוגמה.

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

מדידת ביצועים

קודם פותחים את אפליקציית הדוגמה בתצוגת מסך מלא:

  1. לוחצים על Remix to Edit כדי לאפשר עריכה של הפרויקט.
  2. כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה. לאחר מכן לוחצים על מסך מלא מסך מלא.

מריצים בדיקת ביצועים של Lighthouse בדף כדי לקבוע את רמת הביצועים הבסיסית:

  1. מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את DevTools.
  2. לוחצים על הכרטיסייה Lighthouse.
  3. לוחצים על נייד.
  4. מסמנים את התיבה ביצועים. (אפשר למחוק את שאר תיבות הסימון בקטע 'ביקורות').
  5. לוחצים על הדמיה של 3G מהיר, האטה פי 4 במהירות התגובה של יחידת העיבוד המרכזית (CPU).
  6. מסמנים את התיבה Clear Storage.
  7. לוחצים על הרצת ביקורות.

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

צילום מסך של ביקורת Lighthouse שמוצגים בו זמן FCP של 2.4 שניות ושני הזדמנויות: הסרת משאבים שחוסמים את העיבוד ויצירת קישור מראש למקורות נדרשים.

דחיית JavaScript של צד שלישי

בבדיקה הסרת משאבים שחוסמים עיבוד זוהתה אפשרות לחסוך זמן על ידי דחיית סקריפט שמגיע מ-d3js.org:

צילום מסך של הביקורת 'הסרת משאבים שחוסמים עיבוד', שבו הדגשה של הסקריפט d3.v3.min.js.

D3.js היא ספריית JavaScript ליצירת תצוגות חזותיות של נתונים. הקובץ script.js באפליקציה לדוגמה משתמש בפונקציות שירות D3 כדי ליצור את תרשים הקו מסוג SVG ולצרף אותו לדף. סדר הפעולות חשוב כאן: הפונקציה script.js צריכה לפעול אחרי שמנתחים את המסמך וטעינה של ספריית D3, ולכן היא כלולה ממש לפני התג הסוגר </body> ב-index.html.

עם זאת, סקריפט D3 נכלל ב-<head> של הדף, שחוסם את הניתוח של שאר המסמך:

צילום מסך של index.html עם תג סקריפט מודגש בחלק העליון.

שני מאפייני קסם יכולים לבטל את חסימת המנתח כשמוסיפים אותם לתג הסקריפט:

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

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

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

שלב 1: טוענים את הסקריפט באופן אסינכרוני באמצעות המאפיין defer

בשורה 17 בקובץ index.html, מוסיפים את המאפיין defer לרכיב <script>:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

שלב 2: מוודאים שהפעולות מתבצעות בסדר הנכון

עכשיו ש-D3 נדחה, script.js יפעל לפני ש-D3 מוכן, תתקבל שגיאה.

סקריפטים עם המאפיין defer מופעלים לפי הסדר שבו הם צוינו. כדי לוודא ש-script.js יופעל אחרי ש-D3 יהיה מוכן, מוסיפים לו את defer ומעבירים אותו ל-<head> של המסמך, ממש אחרי הרכיב <script> של D3. עכשיו הוא לא חוסם יותר את המנתח, וההורדה מתחילה מוקדם יותר.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

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

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

באפליקציית הדוגמה יש סרטון YouTube שמוטמע ב-iframe. כדי לבדוק כמה בקשות הדף שולח ואילו בקשות מגיעות מה-iframe המוטמע של YouTube:

  1. כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה. לאחר מכן לוחצים על מסך מלא מסך מלא.
  2. מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את DevTools.
  3. לוחצים על הכרטיסייה רשתות.
  4. מסמנים את התיבה Disable cache (השבתת המטמון).
  5. בתפריט הנפתח Throttling, בוחרים באפשרות Fast 3G.
  6. לטעון מחדש את הדף.

צילום מסך של חלונית הרשת ב-DevTools.

בחלונית Network (רשת) מוצג שהדף שלח סה"כ 28 בקשות והעביר כמעט 1MB של משאבים דחוסים.

כדי לזהות את הבקשות שנשלחו על ידי iframe ב-YouTube, צריך לחפש את מזהה הווידאו 6lfaiXM6waw בעמודה יוזם. כדי לקבץ את כל הבקשות לפי דומיין:

  • בחלונית Network, לוחצים לחיצה ימנית על כותרת עמודה.

  • בתפריט הנפתח, בוחרים בעמודה Domains.

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

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

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

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

שלב 1: מונעים את טעינת הסרטון בשלב הראשון

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

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src הוא מאפיין נתונים שמאפשר לאחסן מידע נוסף ברכיבי HTML רגילים. אפשר לתת למאפיין נתונים שם כלשהו, כל עוד הוא מתחיל ב-'data-'.

פשוט לא ניתן יהיה לטעון iframe ללא src.

שלב 2: שימוש ב-Intersection Observer כדי לטעון את הסרטון באיטרציה

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

כדי להתחיל, יוצרים קובץ חדש ומעניקים לו את השם lazy-load.js:

  • לוחצים על קובץ חדש ומעניקים לו שם.
  • לוחצים על Add This File (הוספת הקובץ הזה).

מוסיפים את תג הסקריפט לכותרת של המסמך:

 <script src="/lazy-load.js" defer></script>

ב-lazy-load.js, יוצרים IntersectionObserver חדש ומעבירים לו פונקציית קריאה חוזרת להרצה:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

עכשיו נותנים ל-observer רכיב יעד לצפייה (במקרה הזה, ה-iframe של הסרטון) על ידי העברה שלו כארגומנטים בשיטה observe:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback מקבל רשימה של אובייקטים מסוג IntersectionObserverEntry ואת האובייקט IntersectionObserver עצמו. כל רשומה מכילה רכיב target ומאפיינים שמתארים את המימדים, המיקום, הזמן שבו היא נכנסה למסך ועוד. אחד מהמאפיינים של IntersectionObserverEntry הוא isIntersecting – ערך בוליאני ששווה ל-true כשהרכיב נכנס למסך.

בדוגמה הזו, target הוא iframe. הערך של isIntersecting שווה ל-true כשהרכיב target נכנס לאזור התצוגה. כדי לראות את הפעולה הזו בפעולה, מחליפים את callback בפונקציה הבאה:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה. לאחר מכן לוחצים על מסך מלא מסך מלא.
  2. מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את DevTools.
  3. לוחצים על הכרטיסייה מסוף.

כדאי לנסות לגלול למעלה ולמטה. הערך של isIntersecting ישתנה ורכיב היעד יירשם ביומן במסוף.

כדי לטעון את הסרטון כשהמשתמש גולל למיקום שלו, משתמשים ב-isIntersecting כתנאי להפעלת פונקציית loadElement, שמקבלת את הערך מ-data-src של רכיב iframe ומגדירה אותו כמאפיין src של רכיב iframe. ההחלפה הזו מפעילה את הטעינה של הסרטון. לאחר מכן, אחרי שהסרטון נטען, מפעילים את השיטה unobserve ב-observer כדי להפסיק את הצפייה ברכיב היעד:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

שלב 3: הערכה מחדש של הביצועים

כדי לראות איך השתנו הגודל ומספר המשאבים, פותחים את החלונית רשת בכלי הפיתוח וטוענים מחדש את הדף. בחלונית Network (רשת) מוצג שהדף שלח 14 בקשות ורק 260KB. זה שיפור משמעותי!

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

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

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

הוספת המאפיין rel=preconnect לקישור מורה לדפדפן ליצור חיבור לדומיין לפני שליחת הבקשה למשאב הזה. מומלץ להשתמש במאפיין הזה במקורות שמספקים משאבים שאתם בטוחים שהדף זקוק להם.

בבדיקת Lighthouse שביצעתם בשלב הראשון, בקטע יצירת קישור מראש למקורות נדרשים, הוצע לכם לחסוך כ-400 אלפיות השנייה על ידי יצירת חיבורים מוקדמים לכתובות staticxx.facebook.com ו-youtube.com:

צריך להתחבר מראש לביקורת מקורות נדרשת עם הדגשה של הדומיין staticxx.facebook.com.

מכיוון שסרטון YouTube נטען עכשיו באיטרציה, נשאר רק staticxx.facebook.com, המקור של הווידג'ט לשיתוף ברשתות החברתיות. כדי ליצור חיבור מוקדם לדומיין הזה, פשוט מוסיפים תג <link> ל-<head> של המסמך:

  <link rel="preconnect" href="https://staticxx.facebook.com">

הערכה מחדש של הביצועים

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

ביקורת של Lighthouse שמראה זמן טעינה ראשוני של שנייה אחת וציון ביצועים של 99.