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

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

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

תאימות דפדפן

כל הדפדפנים העיקריים כוללים bfcache, כולל Chrome מגרסה 96, ‏ Firefox ו-Safari.

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

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

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

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

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

השימוש ב-bfcache מאפשר טעינת דפים מהירה יותר במהלך ניווט אחורה וקדימה.

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

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

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

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

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

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

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

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

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

bfcache ומסגרות iframe

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

אפשר גם לחסום את השימוש ב-bfcache בפריים הראשי אם iframe מוטמע משתמש בממשקי API שחוסמים את השימוש הזה. כדי למנוע זאת, אפשר להשתמש במדיניות ההרשאות שמוגדרת בפריים הראשי או במאפייני sandbox.

bfcache ואפליקציות בדף יחיד (SPA)

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

ממשקי API למעקב אחרי bfcache

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

האירועים הראשיים שמשמשים למעקב אחרי bfcache הם אירועי המעבר לדף pageshow ו-pagehide, שנתמכים ברוב הדפדפנים.

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

מעקב אחרי שחזור דף מ-bfcache

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

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 מופעל כשדפים משוחזרים מ-bfcache (מיד לפני האירוע pageshow) וכשמשתמש חוזר לכרטיסייה קפואה ברקע. אם רוצים לעדכן את המצב של דף אחרי שהוא הוקפא (כולל דפים ב-bfcache), אפשר להשתמש באירוע resume. לעומת זאת, אם רוצים למדוד את שיעור ההיטים של האתר ב-bfcache, צריך להשתמש באירוע pageshow. במקרים מסוימים, ייתכן שתצטרכו להשתמש בשניהם.

פרטים על שיטות מומלצות למדידת bfcache זמינים במאמר איך bfcache משפיע על ניתוח נתונים ומדידה של ביצועים.

מעקב אחרי מועד הכניסה של דף ל-bfcache

האירוע pagehide מופעל כשדף מסוים פורק או כשהדפדפן מנסה להעביר אותו ל-bfcache.

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

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

אופטימיזציה של הדפים ל-bfcache

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

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

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

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

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

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

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

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

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

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

בגלל חוסר האמינות שלו וההשפעה על הביצועים של bfcache, אנחנו ב-Chrome שוקלים להוציא משימוש את האירוע unload.

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

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

Permissions-Policy: unload=()

כך גם מונעים מצדדים שלישיים או מתוספים להאט את האתר על ידי הוספת טיפולי פריקה (unload handlers) והפיכת האתר לבלתי מתאים ל-bfcache.

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

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

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

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

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

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

עדכון נתונים לא עדכניים או רגישים אחרי שחזור של bfcache

אם באתר שלכם נשמר מצב המשתמש – במיוחד מידע רגיש של משתמשים – צריך לעדכן או לנקות את הנתונים האלה אחרי שדף משווח מ-bfcache.

לדוגמה, אם משתמש מנווט לדף תשלום ולאחר מכן מעדכן את עגלת הקניות, ניווט חזרה עלול לחשוף מידע לא עדכני אם דף לא עדכני ישוחזר מ-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();
  }
});

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

שחזור של מודעות ו-bfcache

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

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

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

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

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

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

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

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

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

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

כתוצאה מכך, דפדפנים מסוימים לא ינסו להעביר דף ל-bfcache בתרחישים הבאים:

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

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

בדוגמה הבאה מוסבר איך לוודא שדפים שמשתמשים ב-IndexedDB עומדים בדרישות לשימוש ב-bfcache, על ידי סגירת חיבור פתוח בבורר האירועים 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 leaves.
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 יכולים לעזור לכם לבדוק את הדפים כדי לוודא שהם מותאמים ל-bfcache, ולזהות בעיות שעשויות למנוע מהם לעמוד בדרישות.

כדי לבדוק דף:

  1. עוברים לדף ב-Chrome.
  2. בכלי הפיתוח, עוברים אל Application (אפליקציה) -> Back-forward Cache (מטמון 'הקודם' ו'הבא').
  3. לוחצים על הלחצן הרצת הבדיקה. לאחר מכן, כלי הפיתוח מנסים לנווט למקום אחר ולחזור כדי לקבוע אם אפשר לשחזר את הדף מ-bfcache.
החלונית 'מטמון לדף הקודם/הבא' ב-DevTools
החלונית Back-forward Cache ב-DevTools.

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

דיווח של כלי הפיתוח על כך שדף שוחזר בהצלחה מ-bfcache
דף ששוחזר בהצלחה.

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

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

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

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

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

איך bfcache משפיע על ניתוח הנתונים ומדידה של הביצועים

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

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

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

כדאי גם למדוד אם נעשה שימוש ב-bfcache, כדי לזהות דפים שלא משתמשים ב-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';
    });
  }
});

כדי לחשב את יחס ההיטים של bfcache, משתמשים בספירה של back_forward ניווטים ושל back_forward_cache ניווטים.

חשוב לזכור שיש כמה תרחישים, שאינם בשליטת בעלי האתר, שבהם הניווט לאחור/קדימה לא ישתמש ב-bfcache, כולל:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • במדד Largest Contentful Paint ‏ (LCP), משתמשים בדלתא בין חותמת הזמן של האירוע pageshow לבין חותמת הזמן של המסגרת המוצגת הבאה, כי כל הרכיבים במסגרת יוצגו באותו זמן. במקרה של שחזור של bfcache, הערכים של LCP ו-FCP זהים.
  • לגבי המדד מהירות התגובה לאינטראקציה באתר (INP), ממשיכים להשתמש במדד הנוכחי למעקב אחר ביצועים, אבל מאפסים את ערך ה-INP הנוכחי ל-0.
  • במדד Cumulative Layout Shift‏ (CLS), ממשיכים להשתמש במדד המעקב אחר הביצועים הקיים, אבל מאפסים את ערך ה-CLS הנוכחי ל-0.

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

ספריית JavaScript של web-vitals תומכת בשחזור של bfcache במדדים שהיא מדווחת עליהם.

משאבים נוספים