אופטימיזציה של קוד 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. באמצעות Intersection Observer API אפשר לרשום פונקציית קריאה חוזרת שתתבצע בכל פעם שרכיב שאחריו רוצים לעקוב נכנס או יוצא מחלון התצוגה.

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

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

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

 <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: הערכה מחדש של הביצועים

כדי לראות איך השתנו הגודל ומספר המשאבים, פותחים את החלונית רשת בכלי הפיתוח וטוענים מחדש את הדף. בחלונית רשת מוצג שהדף שלח 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.