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

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

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

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

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

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

  • הטמעת סרטון

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

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

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

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

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

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

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

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

  1. מקישים על 'Control+Shift+J' (או על 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
  2. לוחצים על הכרטיסייה Lighthouse.
  3. לוחצים על Mobile (נייד).
  4. מסמנים את התיבה Performance (ביצועים). (אפשר למחוק את שאר תיבות הסימון בקטע 'ביקורות').
  5. לוחצים על Simulated Fast 3G, 4x CPU Slowdown.
  6. מסמנים את התיבה נקה נפח אחסון.
  7. לוחצים על Run Reviews.

כשמריצים ביקורת במחשב, התוצאות המדויקות עשויות להשתנות, אבל כדאי להבחין שזמן המהירות שבה נטען רכיב התוכן הראשון (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) כדי לפתוח את כלי הפיתוח.
  3. לוחצים על הכרטיסייה רשתות.
  4. מסמנים את התיבה Disable cache (השבתת מטמון).
  5. בוחרים באפשרות Fast 3G בתפריט הנפתח Throttling.
  6. לטעון מחדש את הדף.

צילום מסך של החלונית DevTools Network.

בחלונית רשת אפשר לראות שהדף ביצע 28 בקשות בסך הכול והועבר כמעט 1MB של משאבים דחוסים.

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

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

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

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

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

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

צריך להתחבר מראש למקורות הנדרשים

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

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

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

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

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

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

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

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

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