חיפוש ]

טעינת עצלה של סקריפטים JavaScript לשיפור ביצועי האתר

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

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

בכך תשפרו את זמן הטעינה ותקבלו מדדי Core Web Vitals טובים יותר, במיוחד Interaction to Next Paint (INP) שמושפע ישירות מכמות ה-JavaScript שרצה בעמוד.

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

מתי להשתמש בטעינת סקריפטים לפי דרישה

ישנן שלוש אסטרטגיות עיקריות לטעינת JavaScript לא קריטי:

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

פוסט זה מתמקד בגישה השלישית. היא היעילה ביותר עבור Core Web Vitals מכיוון שהיא מסירה לחלוטין JavaScript שאינו בשימוש מטעינת העמוד הראשונית.

הפונקציה loadScript

לעניינו, בכדי להשתמש בטכניקה זו של Lazy Loading, בואו נגדיר פונקציה בשם loadScript:

function loadScript(url) {
  let isLoaded = document.querySelectorAll('.search-script');
  if(isLoaded.length > 0) {
    return;
  }

  let myScript = document.createElement("script");
  myScript.src = url;
  myScript.className = 'search-script';
  document.body.appendChild(myScript);
}

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

לאחר מכן אנו יוצרים אלמנט מסוג script באמצעות document.createElement ומעבירים לו את כתובת ה-URL שתשמש עבור התכונה src של הסקריפט אותו נטען בטעינה עצלה.

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

הפעלת הסקריפט באינטראקציית המשתמש

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

let searchInput = document.querySelector('#trigger-overlay');
searchInput.addEventListener('click', function (e) {
    loadScript('/path/to/search.js');
});

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

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

אגב, לתוסף WP-Rocket ישנה אפשרות דומה בשם Delay Javascript Execution. היא פועלת מעט שונה – היא מתבססת על User Interaction כלשהו באתר ולא אינטראקציה ספציפית שאתם יכולים לקבוע.

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

טעינת סקריפטים עם Intersection Observer

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

function loadScriptOnVisible(selector, url) {
  const target = document.querySelector(selector);
  if (!target) return;

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        loadScript(url);
        observer.disconnect();
      }
    });
  });

  observer.observe(target);
}

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

הוספת Callback לפונקציה loadScript

הפונקציה הבסיסית loadScript לא מאפשרת לדעת מתי הסקריפט סיים להיטען. ניתן להוסיף callback או להחזיר Promise:

function loadScript(url) {
  return new Promise((resolve, reject) => {
    const isLoaded = document.querySelector(`script[src="${url}"]`);
    if (isLoaded) {
      resolve();
      return;
    }

    const script = document.createElement('script');
    script.src = url;
    script.onload = resolve;
    script.onerror = reject;
    document.body.appendChild(script);
  });
}

עכשיו ניתן לשרשר פעולות שתלויות בטעינת הסקריפט:

searchInput.addEventListener('click', async function() {
  await loadScript('/path/to/search.js');
  initializeSearch();
});

אינטגרציה עם וורדפרס

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

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

שאלות נפוצות

שאלות נפוצות בנושא טעינה עצלה של JavaScript:

מה ההבדל בין defer, async וטעינת סקריפטים לפי דרישה?
תכונת defer מורידה את הסקריפט ברקע ומבצעת אותו לאחר ניתוח ה-HTML, תוך שמירה על סדר. תכונת async מורידה ומבצעת מיד כשמוכן, ללא סדר מוגדר. טעינה לפי דרישה מביאה ומבצעת את הסקריפט רק כשאירוע ספציפי מתרחש, כמו לחיצה או גלילה. טעינה לפי דרישה מספקת את הביצועים הטובים ביותר מכיוון שהסקריפט לעולם לא נטען אלא אם נדרש.
האם טעינה עצלה של JavaScript משפרת Core Web Vitals?
כן. טעינה עצלה של JavaScript משפרת ישירות את Interaction to Next Paint (INP) על ידי הפחתת כמות ה-JavaScript שמבוצעת בזמן טעינת העמוד. היא גם עוזרת ל-Largest Contentful Paint (LCP) על ידי שחרור ה-Main Thread לרינדור. ככל שפחות JavaScript רץ בטעינה הראשונית, כך העמוד מרגיש מגיב יותר.
מתי להשתמש ב-Intersection Observer במקום אירוע לחיצה?
השתמשו ב-Intersection Observer כשהסקריפט קשור לאלמנט גלוי בעמוד, כמו מפה מוטמעת, קטע תגובות או ווידג'ט מתחת לקו הקיפול. השתמשו באירוע לחיצה כשהסקריפט קשור לפעולה ספציפית של המשתמש כמו לחיצה על כפתור או אייקון. שתי הגישות מונעות טעינה מיותרת.
האם הסקריפט ייטען כל פעם שהמשתמש לוחץ על הכפתור?
לא. הפונקציה loadScript כוללת בדיקה האם הסקריפט כבר נטען. אם כן, הפונקציה חוזרת מיד ללא הוספת תגית script כפולה. זה מבטיח שהסקריפט נטען פעם אחת בלבד ללא קשר לכמות הפעמים שהמשתמש מפעיל את האירוע.
האם ניתן להשתמש בטכניקה זו עם תוספי וורדפרס?
כן, אך זה דורש הסרת הסקריפט של התוסף ממערכת ה-enqueue הרגילה של וורדפרס ואז טעינתו לפי דרישה עם הפונקציה loadScript. לחלופין, ניתן להשתמש בתכונת Delay JavaScript Execution של WP Rocket או ב-Plugin Organizer לשליטה סלקטיבית על אילו סקריפטים נטענים באילו עמודים.
האם טעינת סקריפטים לפי דרישה תואמת לכל הדפדפנים?
כן. השיטות document.createElement ו-appendChild המשמשות בפונקציה loadScript נתמכות על ידי כל הדפדפנים המודרניים ואף ישנים יותר כמו IE9+. ה-Intersection Observer API נתמך על ידי כל הדפדפנים המודרניים. עבור דפדפנים ישנים מאוד, ניתן להשתמש ב-polyfill או לחזור לטעינה רגילה של הסקריפט.

סיכום

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

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

דיון ותגובות
6 תגובות  ]
  • שי 16 יוני 2021, 10:42

    תודה על המאמר אך הפונקציה מפילה לי את האתר.. חשבתי שחסר סיומת ); בסוף הפונקציה אך עדיין האתר נופל..

    אשמח לדעת איפה טעיתי..
    תודה!

  • שי 20 יוני 2021, 10:51

    כנראה בלא נכון..
    תוכל לכוון אותי איפה להוסיף?
    תודה!

    • רועי יוסף 5 מרץ 2022, 18:45

      אתה אמור להוסיף אותו בקובץ JavaScript כלשהו הנטען באתר שלך…

  • chava kaminer 3 מרץ 2022, 19:26

    איפה אני מוסיפה את הקוד הזה באתר וורדפרס?

    • רועי יוסף 5 מרץ 2022, 18:45

      את אמורה להוסיף אותו בקובץ JavaScript כלשהו הנטען באתר שלך…

השאירו תגובה

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

Savvy WordPress Development official logo