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

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

זה הזמן לקפל

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

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

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

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

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

אם הערך של rootMargin נראה דומה לערכים שציינתם לשירות CSS margin שלך, כי כך זה קורה! במקרה הזה, הפרמטר השוליים התחתוניים של הרכיב שנצפה (אזור התצוגה של הדפדפן כברירת מחדל, אבל אפשר לשנות את זה לרכיב ספציפי באמצעות המאפיין root) מורחב ב-256 פיקסלים. כלומר, פונקציית הקריאה החוזרת תפעל כשרכיב תמונה בטווח של 256 פיקסלים מאזור התצוגה, והתמונה תתחיל להיטען לפני שהמשתמש רואה אותו בפועל.

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

שינוי פריסה ו-placeholders

טעינה מדורגת של מדיה עלולה לגרום לתזוזה בפריסה אם לא משתמשים ב-placeholders. השינויים האלה עלולים לבלבל את המשתמשים ולהפעיל פריסת DOM יקרה פעולות שצורכות משאבי מערכת ותורמות ל-jank. לכל הפחות, כדאי להשתמש ב-placeholder בצבע אחיד עם אותם מידות כמו תמונת יעד, או טכניקות כמו LQIP או SQIP שמרמז על התוכן של מדיה לפני שהוא נטען.

לתגי <img>, קודם צריך שה-src יצביע על placeholder עד מתעדכן בכתובת ה-URL של התמונה הסופית. להשתמש במאפיין poster ב רכיב <video> שמפנה לתמונה של placeholder. בנוסף, צריך להשתמש ב-width וב- height גם בתג <img> וגם בתג <video>. כך אפשר להבטיח מעבר מ-placeholder לתמונות סופיות לא ישנה את הגודל לאחר עיבוד של האלמנט בזמן שהמדיה נטענת.

עיכובים בפענוח התמונה

טעינת תמונות גדולות ב-JavaScript ושחרורן ב-DOM עלולה לפגוע ה-thread הראשי, שגורם לממשק המשתמש לא להגיב למשך זמן קצר בזמן הפענוח. מפענחים תמונות באופן אסינכרוני באמצעות decode אמצעי תשלום לפני הכנסתם ל-DOM יכול להפחית את רמת העומס מהסוג הזה, אבל חשוב להיזהר: פיצ'ר זה עדיין לא זמין בכל מקום, והוא מוסיף מורכבות ללוגיקת הטעינה הדרגתית. אם ברצונך להשתמש בו, עליך לבדוק זאת. מתחת לתוכניות האופן שבו ניתן להשתמש ב-Image.decode() עם חלופה:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

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

כשדברים לא נטענים

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

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

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

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

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

זמינות של JavaScript

אין להניח ש-JavaScript תמיד זמין. אם בכוונתך תמונות עם טעינה מדורגת, כדאי להציע תגי עיצוב של <noscript> שיציגו תמונות ה-JavaScript של בקשות התמיכה לא זמין. הדוגמה הכי פשוטה לחלופה, כוללת באמצעות רכיבי <noscript> כדי להציג תמונות אם JavaScript מושבת:

אני תמונה!

אם JavaScript מושבת, המשתמשים יראו גם את תמונת ה-placeholder וגם את שמכילה את הרכיבים <noscript>. כדי לקבל מסלול באזור הזה, מחלקה של no-js בתג <html>, כמו למשל:

<html class="no-js">

לאחר מכן צריך להציב שורה אחת של סקריפט מוטבע בתוך <head> לפני גיליונות סגנונות כלשהם נשלחות באמצעות תגי <link> שמסירים את המחלקה no-js מ-<html> אם JavaScript מופעל:

<script>document.documentElement.classList.remove("no-js");</script>

לבסוף, השתמשו ב-CSS מסוים כדי להסתיר רכיבים עם סוג של עצלנות JavaScript לא זמין:

.no-js .lazy {
  display: none;
}

הפעולה הזו לא מונעת טעינה של תמונות placeholder, אבל התוצאה שמתקבלת ורצויות. אנשים שהשביתו את JavaScript יראו משהו יותר מאשר placeholder של תמונות, שטוב יותר מאשר placeholders וללא תוכן תמונות משמעותי הכול.