מטמון לדף הקודם/הבא

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

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

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

תאימות דפדפן

bfcache נתמכת ב-Firefox וב-Safari במשך שנים רבות, במחשבים ובניידים.

החל מגרסה 86, Chrome תומך במטמון לדף הקודם/הבא לניווט בין אתרים ב-Android לאחוז קטן מהמשתמשים. בגרסאות הבאות, התמיכה הנוספת הושקה בהדרגה. מגרסה 96, ההגדרה bfcache מופעלת לכל משתמשי Chrome במחשבים ובניידים.

מידע בסיסי על bfcache

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

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

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

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

בסרטון שלמעלה, הדוגמה עם bfcache היא די מהירה יותר מהדוגמה בלעדיה.

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

נתוני השימוש ב-Chrome מראים ש-1 מכל 10 ניווטים במחשב ו-1 מכל 5 ניווטים בנייד הם אחורה או קדימה. כשהמטמון לדף הקודם פועל, דפדפנים יכולים למנוע את העברת הנתונים ואת הזמן שמשקיעים בטעינה של מיליארדי דפי אינטרנט בכל יום!

איך פועל 'מטמון'

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

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

התשובה היא שדפדפנים משהים את ההפעלה של טיימרים בהמתנה או הבטחות שלא נפתרו – למעשה כל המשימות הממתינות בתורים של המשימות ב-JavaScript – וממשיכים במשימות העיבוד כשהדף משוחזר (או אם) מהמטמון לדף הקודם/הבא.

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

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

המטמון לדף הקודם/הבא ואפליקציות בדף יחיד (SPA)

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

ממשקי API לצפייה במטמון לדף הקודם/הבא

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

האירועים העיקריים שמשמשים לצפייה במטמון לדף הקודם/הבא הם אירועי מעבר דפיםpageshow ו-pagehide – שקיימים כל הזמן שבו bfcache קיימת ונתמכים בכמעט כל הדפדפנים שבהם אנחנו משתמשים היום.

האירועים החדשים יותר של מחזור החיים של הדף, freeze ו-resume, נשלחים גם כשדפים נכנסים למטמון לדף הקודם או יוצאים ממנו, וגם במצבים אחרים. לדוגמה, כשכרטיסייה ברקע קופאת כדי לצמצם את השימוש במעבד (CPU). הערה: בשלב זה, אירועים במחזור החיים של הדף נתמכים רק בדפדפנים המבוססים על Chromium.

לראות מתי דף משוחזר ממטמון לדף הקודם/הבא

האירוע pageshow מופעל מיד אחרי האירוע load כשהדף נטען לראשונה ובכל פעם שהדף שוחזר מהמטמון לדף הקודם/הבא. לאירוע pageshow יש מאפיין persisted, אם הדף שוחזר מהמטמון לדף הקודם/הבא (וגם false אם לא), יהיה true. אפשר להשתמש במאפיין persisted כדי להבחין בין טעינות רגילות של דפים לבין שחזורים של מטמון לדף הקודם/הבא. לדוגמה:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    console.log('This page was restored from the bfcache.');
  } else {
    console.log('This page was loaded normally.');
  }
});

בדפדפנים שתומכים ב-Page Lifecycle API, האירוע resume יופעל גם כשהדפים ישוחזרו מהמטמון לדף הקודם/הבא (מיד לפני האירוע pageshow), אבל הוא גם יופעל כשמשתמש ייכנס שוב לכרטיסיית רקע שקופאת. אם רוצים לעדכן מצב של דף אחרי שהוא קפוא (כולל דפים במטמון לדף הקודם/הבא), אפשר להשתמש באירוע resume, אבל אם רוצים למדוד את שיעור ההיטים של המטמון לדף הקודם/הבא של האתר, צריך להשתמש באירוע pageshow. במקרים מסוימים, יכול להיות שתצטרכו להשתמש בשניהם.

לראות מתי דף עובר למטמון לדף הקודם/הבא

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

לאירוע pagehide יש גם מאפיין persisted, ואם הוא false, אז תוכלו להיות בטוחים שדף לא עומד להיכנס למטמון לדף הקודם/הבא. עם זאת, אם המאפיין persisted הוא true, לא בטוח שהדף יישמר במטמון. המשמעות היא שהדפדפן intends לשמור את הדף במטמון, אבל ייתכן שיש גורמים שמונעים את שמירתו במטמון.

window.addEventListener('pagehide', (event) => {
  if (event.persisted) {
    console.log('This page *might* be entering the bfcache.');
  } else {
    console.log('This page will unload normally and be discarded.');
  }
});

באופן דומה, האירוע freeze יופעל מיד אחרי האירוע pagehide (אם המאפיין persisted של האירוע הוא true), אבל שוב המשמעות היא רק שהדפדפן intends לשמור את הדף במטמון. יכול להיות שהוא עדיין יצטרך למחוק אותו מכמה סיבות, שמפורטות בהמשך.

אופטימיזציה של הדפים למטמון לדף הקודם/הבא

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

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

אף פעם לא להשתמש באירוע unload

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

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

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

ב-Chrome וב-Firefox במחשבים שולחניים, ב-Chrome וב-Firefox בחרו להפוך דפים לא כשירים למטמון לדף הקודם/הבא אם הם יוסיפו האזנה מסוג unload, דבר שרמת הסיכון שלו נמוכה יותר, אבל גם הרבה דפים נפסלים. Safari ינסה לשמור במטמון חלק מהדפים באמצעות event listener של unload, אבל כדי לצמצם הפסקה פוטנציאלית, הוא לא יפעיל את האירוע unload כשמשתמש מנווט למקום אחר, וכתוצאה מכך האירוע לא אמין מאוד.

בנייד, Chrome ו-Safari ינסו לשמור במטמון דפים עם event listener של unload, כי יש סיכון נמוך יותר לשיבושים כי האירוע unload תמיד לא היה מהימן במיוחד בנייד. מערכת Firefox מתייחסת לדפים שנעשה בהם שימוש ב-unload כדפים שלא מתאימים לשמירה במטמון לדף הקודם/הבא, למעט ב-iOS. לשם כך, כל הדפדפנים צריכים להשתמש במנוע הרינדור WebKit, ולכן ההתנהגות שלו תהיה זהה ל-Safari.

במקום להשתמש באירוע unload, השתמשו באירוע pagehide. האירוע pagehide מופעל בכל המקרים שבהם האירוע unload מופעל כרגע, והוא גם מופעל כשדף מועבר למטמון לדף הקודם/הבא.

למעשה, ב-Lighthouse יש ביקורת no-unload-listeners, שתזהיר מפתחים אם כל JavaScript בדפים שלהם (כולל זה מספריות של צד שלישי) מוסיף פונקציית event listener של unload.

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

שימוש במדיניות הרשאות כדי למנוע שימוש ב-handlers שנטענו בדף

אתרים שלא משתמשים במטפלים באירועים של unload יכולים לוודא שהאירועים האלה לא יתווספו באמצעות מדיניות הרשאות מ-Chrome 115.

Permission-Policy: unload()

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

הוספת beforeunload מאזינים בלבד לפי תנאי

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

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

מה אסור לעשות
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
הקוד שלמעלה מוסיף האזנה ל-beforeunload ללא תנאי.
מה מותר לעשות
function beforeUnloadListener(event) {
  event.preventDefault();
  return event.returnValue = 'Are you sure you want to exit?';
};

// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
  window.addEventListener('beforeunload', beforeUnloadListener);
});

// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
  window.removeEventListener('beforeunload', beforeUnloadListener);
});
הקוד שלמעלה מוסיף האזנה ל-beforeunload רק כשצריך (ומסיר אותו כשאין צורך).

צמצום השימוש ב-Cache-Control: no-store

Cache-Control: no-store היא כותרת HTTP ששרתי אינטרנט יכולים להגדיר בתגובה לתגובות, שמנחה את הדפדפן לא לאחסן את התגובה באף מטמון HTTP. צריך להשתמש במידע הזה למשאבים שמכילים מידע רגיש על המשתמש, למשל דפים שמחייבים התחברות.

המטמון לדף הקודם/הבא הוא לא מטמון HTTP, אבל בעבר כש-Cache-Control: no-store מוגדר במשאב הדף עצמו (בניגוד למשאב משנה כלשהו), הדפדפנים בחרו לא לאחסן את הדף במטמון לדף הקודם/הבא. אנחנו פועלים לשינוי ההתנהגות הזו ב-Chrome תוך שמירה על הפרטיות, אבל כרגע דפים שנעשה בהם שימוש ב-Cache-Control: no-store לא מתאימים לשמירה במטמון לדף הקודם/הבא.

המדיניות Cache-Control: no-store מגבילה את הכשירות של דף מסוים לשמירה במטמון לדף הקודם/הבא, ולכן צריך להגדיר אותו רק בדפים שמכילים מידע רגיש, שלעולם לא מתאימה לשמור במטמון מסוג כלשהו.

עבור דפים שרוצים להציג תמיד תוכן עדכני — והתוכן הזה לא מכיל מידע רגיש — יש להשתמש ב-Cache-Control: no-cache או Cache-Control: max-age=0. ההוראות האלה מורים לדפדפן לאמת מחדש את התוכן לפני הצגתו, והן לא משפיעות על הכשירות של הדף 'מטמון לדף הקודם'.

שימו לב שכאשר דף משוחזר ממטמון לדף הקודם/הבא, הוא משוחזר מהזיכרון, ולא מהמטמון של HTTP. כתוצאה מכך, הוראות כמו Cache-Control: no-cache או Cache-Control: max-age=0 לא נלקחות בחשבון, ולא מתבצע אימות מחדש לפני שהתוכן מוצג למשתמש.

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

עדכון של מידע לא פעיל או רגיש אחרי שחזור bfcache

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

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

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

כדי למנוע מצבים כאלה, תמיד כדאי לעדכן את הדף אחרי אירוע pageshow אם event.persisted הוא true:

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // Do any checks and updates to the page
  }
});

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

window.addEventListener('pageshow', (event) => {
  if (event.persisted && !document.cookie.match(/my-cookie/)) {
    // Force a reload if the user has logged out.
    location.reload();
  }
});

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

שחזור מודעות ומטמון לדף הקודם/הבא

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

באתרים שרוצים לרענן מודעות בשחזור המטמון לדף הקודם/הבא, ואז לרענן רק את המודעות באירוע pageshow כשהערך של event.persisted הוא true, מבלי להשפיע על ביצועי הדף. כדאי לבדוק עם ספק המודעות שלכם, אבל כאן מוצגת דוגמה אחת איך לעשות את זה באמצעות Google Publishing Tag.

הימנעות מהפניות של window.opener

בדפדפנים ישנים יותר, אם הדף נפתח באמצעות window.open() מקישור עם target=_blank, בלי לציין rel="noopener", הדף הפותח יכלול הפניה לאובייקט החלון של הדף הפתוח.

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

כתוצאה מכך, כדאי להימנע מיצירת קובצי עזר מסוג window.opener. אפשר לעשות זאת באמצעות rel="noopener" כשאפשר (שימו לב, זו ברירת המחדל בכל הדפדפנים המודרניים). אם באתר שלכם צריך לפתוח חלון ולשלוט בו דרך window.postMessage() או להפנות ישירות לאובייקט החלון, גם החלון הפתוח וגם קובץ הפתיחה לא יעמדו בדרישות של המטמון לדף הקודם/הבא.

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

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

אם המשימות המתוזמנות האלה של JavaScript ניגשות רק ל-DOM APIs או לממשקי API אחרים שמבודדים רק את הדף הנוכחי, השהיית המשימות האלה בזמן שהדף לא גלוי למשתמש לא תגרום לבעיות.

עם זאת, במקרה שהמשימות האלה מקושרות לממשקי API שאפשר לגשת אליהם גם מדפים אחרים באותו מקור (לדוגמה: IndexedDB, Web Locks, WebSockets וכו'), הדבר עלול להיות בעייתי כי השהיית המשימות האלה עלולה למנוע את הפעלת הקוד בכרטיסיות אחרות.

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

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

לאחר מכן, אם הדף ישוחזר מהמטמון לדף הקודם/הבא, תוכלו לפתוח מחדש את ממשקי ה-API האלה או להתחבר אליהם מחדש (באירוע pageshow או resume).

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

let dbPromise;
function openDB() {
  if (!dbPromise) {
    dbPromise = new Promise((resolve, reject) => {
      const req = indexedDB.open('my-db', 1);
      req.onupgradeneeded = () => req.result.createObjectStore('keyval');
      req.onerror = () => reject(req.error);
      req.onsuccess = () => resolve(req.result);
    });
  }
  return dbPromise;
}

// Close the connection to the database when the user is leaving.
window.addEventListener('pagehide', () => {
  if (dbPromise) {
    dbPromise.then(db => db.close());
    dbPromise = null;
  }
});

// Open the connection when the page is loaded or restored from bfcache.
window.addEventListener('pageshow', () => openDB());

בדיקה כדי לוודא שניתן לשמור את הדפים

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

כדי לבדוק דף מסוים, עוברים אליו ב-Chrome ואז בכלי הפיתוח עוברים אל Application (אפליקציה) > Back-forward cache. לאחר מכן, לוחצים על הלחצן Run Test, וכלי הפיתוח ינסו לנווט למקום אחר ולחזור אליו כדי לבדוק אם אפשר לשחזר את הדף מהמטמון לדף הקודם/הבא.

החלונית 'מטמון לדף הקודם/הבא' בכלי הפיתוח

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

דיווח של דף בכלי הפיתוח שוחזר בהצלחה מהמטמון לדף הקודם/הבא

אם הדף לא שוחזר, בחלונית תופיע הסיבה לכך.

אם אתם, כמפתח, יכולים לטפל בבעיה, יש לציין גם את הסיבה לכך:

הדיווח של כלי הפיתוח נכשל בשחזור דף מהמטמון לדף הקודם/הבא

בצילום המסך שלמעלה, השימוש ב-event listener של unload מונע את ההתאמה של הדף למטמון לדף הקודם/הבא. כדי לפתור את הבעיה, אפשר לעבור מ-unload ולהשתמש ב-pagehide במקום זאת:

מה אסור לעשות
window.addEventListener('unload', ...);
מה מותר לעשות
window.addEventListener('pagehide', ...);

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

איך המטמון לדף הקודם/הבא משפיע על ניתוח נתונים ומדידת ביצועים

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

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

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

הדוגמה הבאה ממחישה איך לעשות זאת עם Google Analytics. הלוגיקה אמורה להיות דומה לכלים אחרים לניתוח נתונים:

// Send a pageview when the page is first loaded.
gtag('event', 'page_view');

window.addEventListener('pageshow', (event) => {
  // Send another pageview if the page is restored from bfcache.
  if (event.persisted) {
    gtag('event', 'page_view');
  }
});

מדידת יחס ההיטים של bfcache

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

// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
   'navigation_type': performance.getEntriesByType('navigation')[0].type;
});

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    // Send another pageview if the page is restored from bfcache.
    gtag('event', 'page_view', {
      'navigation_type': 'back_forward_cache';
    });
  }
});

כשבוחנים את היחס בין back_forward הניווטים ל-back_forward_cache אפשר לחשב את היחס של המטמון לדף הקודם/הבא.

חשוב להבין שיש מספר תרחישים, מחוץ לשליטה של בעלי האתר, שבהם ניווט 'הקודם' ו'הבא' לא ישתמש במטמון לדף הקודם/הבא, כולל:

  • כשהמשתמש סוגר את הדפדפן ומפעיל אותו שוב
  • כשהמשתמש משכפל כרטיסייה.
  • כשמשתמש סוגר כרטיסייה ופותח אותה

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

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

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

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

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

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

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

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

יש כמה דרכים להתמודד עם הבעיה הזו. אחת הדרכים היא להוסיף הערות לכל מדדי טעינת הדף בהתאם לסוג הניווט שלהם: navigate, reload, back_forward או prerender. כך תוכלו להמשיך לעקוב אחרי הביצועים בסוגי הניווט האלה, גם אם ההתפלגות הכוללת נוטה להיות שלילית. הגישה הזו מומלצת למדדי טעינת דפים שלא מתמקדים במשתמש, כמו Time to First Byte (TTFB).

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

ההשפעה על מדדי הליבה לבדיקת חוויית המשתמש באתר

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

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

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

  • במאפיין LCP (המהירות שבה נטען רכיב התוכן הכי גדול (LCP)), אפשר להשתמש בדלטה בין חותמת הזמן של האירוע pageshow לחותמת הזמן של הפריים הבא שצובע (כי כל האלמנטים בתמונה יצוירו באותו זמן). שימו לב שבמקרה של שחזור bfcache, ה-LCP וה-FCP יהיו זהים.
  • בעיכוב לאחר קלט ראשון (FID), אפשר להוסיף מחדש את פונקציות event listener (אותם פונקציות event listener שמשמשות את ה-FID polyfill) באירוע pageshow, ולדווח על FID כעיכוב של הקלט הראשון לאחר שחזור bfcache.
  • בCumulative Layout Shift (CLS), אפשר להמשיך להשתמש ב-Performance Exploreer הקיים – כל מה שצריך לעשות הוא לאפס את הערך הנוכחי ל-0.

לפרטים נוספים על ההשפעה של bfcache על כל מדד, אפשר לעיין בדפי המדריכים הספציפיים של דוח המדדים הבסיסיים של חוויית המשתמש (Core Web Vitals). לקבלת דוגמה ספציפית להטמעה של גרסאות bfcache של המדדים האלה בקוד, תוכלו לקרוא את המאמר בנושא PR שמוסיף אותם לספריית ה-JS של רכיבי האינטרנט.

מקורות נוספים