תמיכה בדפדפנים
דפדפנים מודרניים משהים לפעמים דפים או משמיטים אותם לגמרי כשמשאבים המערכת מוגבלים. בעתיד, הדפדפנים ירצו לעשות זאת באופן יזום כדי לצמצם את צריכת החשמל והזיכרון. Page Lifecycle API מספק וו hooks של מחזור חיים, כדי שהדפים יוכלו לטפל בבטחה בהתערבויות האלה בדפדפן בלי להשפיע על חוויית המשתמש. כדאי לעיין ב-API כדי לבדוק אם כדאי להטמיע את התכונות האלה באפליקציה.
רקע
מחזור החיים של אפליקציות הוא דרך מרכזית שבה מערכות הפעלה מודרניות מנהלות משאבים. ב-Android, ב-iOS ובגרסאות האחרונות של Windows, מערכת ההפעלה יכולה להפעיל ולהפסיק אפליקציות בכל שלב. כך הפלטפורמות האלה יכולות לייעל את המשאבים ולחלק אותם מחדש באופן שמניב את התועלת הרבה ביותר למשתמש.
באינטרנט, לא היה מחזור חיים כזה, ואפשר להמשיך להשתמש באפליקציות ללא הגבלת זמן. כשמפעילים מספר גדול של דפי אינטרנט, יכול להיות שיהיה ביקוש יתר על משאבי מערכת קריטיים כמו זיכרון, מעבד (CPU), סוללה ורשת, וכתוצאה מכך חוויית המשתמש תהיה גרועה.
כבר זמן רב יש בפלטפורמת האינטרנט אירועים שקשורים למצבים במחזור החיים, כמו load
, unload
ו-visibilitychange
. עם זאת, האירועים האלה מאפשרים למפתחים להגיב רק לשינויים במצבים במחזור החיים שהמשתמשים יזמו. כדי שהאינטרנט יפעל בצורה מהימנה במכשירים עם הספק נמוך (וגם כדי לנצל את המשאבים בצורה יעילה יותר באופן כללי בכל הפלטפורמות), הדפדפנים צריכים דרך לממש מראש את המשאבים של המערכת ולתת להם הקצאה מחדש.
למעשה, דפדפנים כיום כבר נוקטים אמצעים פעילים לחיסכון במשאבים לדפים בכרטיסיות ברקע, ודפדפנים רבים (במיוחד Chrome) מעוניינים לעשות הרבה יותר מכך – כדי לצמצם את טביעת הרגל הפחמנית הכוללת של המשאבים.
הבעיה היא שלמפתחים אין דרך להתכונן להתערבויות מהסוג הזה שמבוצעות על ידי המערכת, או אפילו לדעת שהן מתרחשות. כלומר, הדפדפנים צריכים לפעול באופן שמרני, אחרת הם עלולים לגרום לשיבושים בדפי אינטרנט.
Page Lifecycle API מנסה לפתור את הבעיה הזו באמצעות:
- הצגת הקונספט של מצבי מחזור חיים באינטרנט וקביעת סטנדרטים לגביו.
- הגדרת מצבים חדשים שמנוהלים על ידי המערכת ומאפשרים לדפדפנים להגביל את המשאבים שיכולים להיות נצרכים על ידי כרטיסיות מוסתרות או לא פעילות.
- יצירת ממשקי API ואירועים חדשים שמאפשרים למפתחי אתרים להגיב למעברים למצבים החדשים האלה שמנוהלים על ידי המערכת, ומהם.
הפתרון הזה מספק את היכולת לחזות את העתיד, שדרושה למפתחי אינטרנט כדי ליצור אפליקציות עמידות בפני התערבויות במערכת, ומאפשר לדפדפנים לבצע אופטימיזציה של משאבי המערכת באופן אגרסיבי יותר, כך שכל משתמשי האינטרנט נהנים ממנו בסופו של דבר.
בהמשך הפוסט הזה נציג את התכונות החדשות של מחזור החיים של הדף ונבחן את הקשר שלהן לכל המצבים והאירועים הקיימים של פלטפורמת האינטרנט. בנוסף, נספק המלצות ושיטות מומלצות לגבי סוגי העבודה שמפתחים צריכים לבצע (ולא לבצע) בכל מצב.
סקירה כללית של מצבים ואירועים במחזור החיים של הדף
כל המצבים של מחזור החיים של הדף הם נפרדים ובלעדיים, כלומר דף יכול להיות במצב אחד בלבד בכל פעם. בדרך כלל, אפשר לראות את רוב השינויים במצב מחזור החיים של דף באמצעות אירועי DOM (מידע נוסף על החריגים מופיע בהמלצות למפתחים לכל מצב).
הדרך הקלה ביותר להסביר את המצבים במחזור החיים של הדף, וגם את האירועים שמסמנים את המעברים ביניהם, היא באמצעות תרשים:
מדינות
בטבלה הבאה מוסבר כל מצב בפירוט. הוא גם מפרט את המצבים האפשריים לפני ואחרי האירועים שמפתחים יכולים להשתמש בהם כדי לראות את השינויים.
מדינה | תיאור |
---|---|
פעיל |
דף נמצא במצב פעיל אם הוא גלוי ורק צריך להתמקד בקלט.
מצבים קודמים אפשריים: |
פסיבי |
דף נמצא בסטטוס פסיבי אם הוא גלוי ואין בו מוקד קלט.
מצבים קודמים אפשריים:
המצבים הבאים אפשריים: |
מוסתרת |
הדף במצב מוסתר אם הוא לא גלוי (ולא הוקפא, נמחק או נסגר).
מצבים קודמים אפשריים:
המצבים הבאים אפשריים: |
קפוא |
במצב קפוא, הדפדפן משהה את הביצוע של משימות שניתנות להקפאה בתורנויות המשימות של הדף, עד שהדף ינוקה מהקיפאון. המשמעות היא שדברים כמו שעונים של JavaScript וקריאות חוזרות (callbacks) של אחזור לא פועלים. משימות שכבר פועלות יכולות להסתיים (החשובה שבהן היא קריאת החזרה (callback) של דפדפנים מקפיאים דפים כדי לחסוך בשימוש במעבד, בסוללה ובנתונים. הם עושים זאת גם כדי לאפשר ניווט מהיר יותר לאחור או קדימה, וכך למנוע צורך בטעינה מחדש מלאה של הדף.
מצבים קודמים אפשריים:
המצבים הבאים אפשריים: |
Terminated |
הדף נמצא במצב סגור אחרי שהטעינה שלו התחילה, והוא נוקה מהזיכרון על ידי הדפדפן. אי אפשר להתחיל משימות חדשות במצב הזה, וייתכן שמשימות שנמצאות בתהליך יסתיימו אם הן יפעלו יותר מדי זמן.
מצבים קודמים אפשריים:
המצבים הבאים האפשריים: |
Discarded |
הדף במצב discarded (נמחק) כאשר הדפדפן מבטל את הטעינה שלו כדי לשמור על משאבים. במצב הזה לא יכולות לפעול משימות, קריאה חוזרת של אירועים או JavaScript מכל סוג שהוא, כי מחיקה מתרחשת בדרך כלל באילוצי משאבים, שבהם לא ניתן להתחיל תהליכים חדשים. בסטטוס discarded, הכרטיסייה עצמה (כולל כותרת הכרטיסייה וסמל הדף) בדרך כלל גלויה למשתמש, גם אם הדף לא מופיע.
מצבים קודמים אפשריים:
המדינות הבאות האפשריות: |
אירועים
הדפדפנים שולחים הרבה אירועים, אבל רק חלק קטן מהם מאותת על שינוי אפשרי במצב של מחזור החיים של הדף. בטבלה הבאה מפורטים כל האירועים שקשורים למחזור החיים, ומפורטות המצבים שהם יכולים לעבור אליהם ומהם.
שם | פרטים |
---|---|
focus
|
הועבר מיקוד לרכיב DOM.
הערה: אירוע
מצבים קודמים אפשריים:
המצבים הנוכחיים האפשריים: |
blur
|
רכיב DOM איבד את המיקוד.
הערה: אירוע
מדינות קודמות אפשריות:
המצבים הנוכחיים האפשריים: |
visibilitychange
|
הערך של השדה |
freeze
*
|
הדף הוקפא עכשיו. משימות שאפשר להקפיא אותן בתורי המשימות בדף לא יופעלו.
מצבים קודמים אפשריים:
המצבים הנוכחיים האפשריים: |
resume
*
|
הדפדפן המשיך בדף מקופא.
מצבים קודמים אפשריים:
המצבים הקיימים האפשריים: |
pageshow
|
מתבצע מעבר לרשומה בהיסטוריית הסשנים. הפעולה יכולה להיות טעינת דף חדש לגמרי או דף שנלקח
מהמטמון לדף הקודם/הבא. אם הדף
נלקח מהמטמון לדף הקודם/הבא, המאפיין
|
pagehide
|
מתבצעת מעבר מרשומה של היסטוריית סשנים. אם המשתמש מנווט לדף אחר והדפדפן יכול להוסיף את הדף הנוכחי למטמון של דפים קודמים/באים כדי לעשות בו שימוש חוזר מאוחר יותר, הערך של המאפיין
הסטטוסים הקודמים האפשריים:
מצבים אפשריים נוכחיים: |
beforeunload
|
החלון, המסמך והמשאבים שלו עומדים לרדת משימוש. המסמך עדיין גלוי והאירוע עדיין ניתן לביטול בשלב הזה.
חשוב: צריך להשתמש באירוע
הסטטוסים הקודמים האפשריים:
הסטטוסים האפשריים הנוכחיים: |
unload
|
מתבצעת טעינה של הדף.
אזהרה: אף פעם לא מומלץ להשתמש באירוע
הסטטוסים הקודמים האפשריים:
הסטטוסים האפשריים הנוכחיים: |
* סימן שמציין אירוע חדש שהוגדר על ידי Page Lifecycle API
תכונות חדשות שנוספו ב-Chrome 68
בתרשים הקודם מוצגות שתי סטטוסים שהמערכת מפעילה ולא המשתמש: קפוא ומושלך. כפי שצוין קודם, דפדפנים כבר מקפיאים מדי פעם כרטיסיות מוסתרות ומבטלים אותן (לפי שיקול דעתם), אבל למפתחים אין דרך לדעת מתי זה קורה.
ב-Chrome 68, מפתחים יכולים עכשיו לראות מתי כרטיסייה מוסתרת קופאת ומתי היא מפשירה, על ידי האזנה לאירועים freeze
ו-resume
ב-document
.
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
החל מגרסה 68 של Chrome, האובייקט document
כולל עכשיו מאפיין wasDiscarded
ב-Chrome במחשב (בבעיה הזו מתבצע מעקב אחרי תמיכה ב-Android). כדי לקבוע אם דף הועבר ללא שימוש בזמן שהיה בכרטיסייה מוסתרת, אפשר לבדוק את הערך של המאפיין הזה בזמן טעינת הדף (הערה: צריך לטעון מחדש דפים שהועברו ללא שימוש כדי להשתמש בהם שוב).
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
המלצות למפתחים לכל מצב – כאן מפורטות המלצות לגבי הפעולות שחשוב לבצע באירועים freeze
ו-resume
, וגם איך לטפל בדפים שנדחים ולהתכונן לכך.
בחלקים הבאים מופיעה סקירה כללית של האופן שבו התכונות החדשות משתלבות באירועים ובמצבים הקיימים בפלטפורמת האינטרנט.
איך לצפות במצבים של מחזור החיים של הדף בקוד
במצבים פעיל, פסיבי ומוסתר, אפשר להריץ קוד JavaScript שקובע את המצב הנוכחי של מחזור החיים של הדף באמצעות ממשקי API קיימים של פלטפורמות אינטרנט.
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
לעומת זאת, אפשר לזהות את מצבי הקפאה וסופית רק ב-event event listener שלהם (freeze
ו-pagehide
) בהתאם לשינויים במצב.
איך עוקבים אחרי שינויים במצב
על בסיס הפונקציה getState()
שהוגדרה קודם לכן, תוכלו לראות את כל השינויים במצב של מחזור החיים של הדף באמצעות הקוד הבא.
// Stores the initial state using the `getState()` function (defined above).
let state = getState();
// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
const prevState = state;
if (nextState !== prevState) {
console.log(`State change: ${prevState} >>> ${nextState}`);
state = nextState;
}
};
// Options used for all event listeners.
const opts = {capture: true};
// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
window.addEventListener(type, () => logStateChange(getState()), opts);
});
// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
// In the freeze event, the next state is always frozen.
logStateChange('frozen');
}, opts);
window.addEventListener('pagehide', (event) => {
// If the event's persisted property is `true` the page is about
// to enter the back/forward cache, which is also in the frozen state.
// If the event's persisted property is not `true` the page is
// about to be unloaded.
logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);
הקוד הזה מבצע שלוש פעולות:
- הגדרת המצב הראשוני באמצעות הפונקציה
getState()
. - הגדרת פונקציה שמקבלת מצב נוסף, ואם יש שינוי, מתעדת את שינויי המצב במסוף.
- הוספת פונקציות תיעוד של אירועי מעקב לכל אירועי מחזור החיים הנדרשים, שמפעילות בתורו את
logStateChange()
ומעבירות את המצב הבא.
חשוב לזכור לגבי הקוד שכל פונקציות ה-event listener מתווספות ל-window
, וכולן מעבירות את הערך {capture: true}
.
יכולות להיות לכך כמה סיבות:
- לא לכל האירועים במחזור החיים של הדף יש את אותו יעד.
pagehide
, ו-pageshow
מופעלים ב-window
;visibilitychange
,freeze
ו-resume
מופעלים ב-document
, ו-focus
ו-blur
מופעלים ברכיבי ה-DOM המתאימים. - רוב האירועים האלה לא עוברים דרך כל ההורים, כלומר אי אפשר להוסיף רכיבי מעקב אחרי אירועים שלא מתעדים אותם לאלמנט אב משותף ולעקוב אחרי כולם.
- שלב הלכידה מתרחש לפני שלבי היעד או הבועה, לכן הוספת מאזינים לשם עוזרת להבטיח שהם יפעלו לפני שקוד אחר יוכל לבטל אותם.
המלצות למפתחים לכל מצב
כמפתחים, חשוב להבין את המצבים במחזור החיים של הדף וגם לדעת איך לזהות אותם בקוד, כי סוג העבודה שצריך לבצע (וגם לא לבצע) תלוי במידה רבה במצב שבו הדף נמצא.
לדוגמה, ברור שאין טעם להציג למשתמש התראה זמנית אם הדף במצב מוסתר. הדוגמה הזו די ברורה, אבל יש המלצות אחרות שלא כל כך ברורות שחשוב לציין.
מדינה | המלצות למפתחים |
---|---|
Active |
המצב פעיל הוא הזמן הקריטי ביותר עבור המשתמש, ולכן זהו הזמן החשוב ביותר שהדף שלכם יגיב לקלט של המשתמש. צריך להפחית את רמת העדיפות של כל עבודה שאינה קשורה לממשק המשתמש שעלולה לחסום את השרשור הראשי, ולהעביר אותה לתקופות חוסר פעילות או להעביר אותה ל-web worker. |
Passive |
במצב פסיבי, המשתמש לא מקיים אינטראקציה עם הדף, אבל הוא עדיין יכול לראות אותו. כלומר, עדכוני ממשק המשתמש והאנימציות עדיין אמורים להיות חלקים, אבל התזמון שבו העדכונים האלה מתרחשים פחות קריטי. כשהסטטוס של הדף משתנה מפעיל לפסיבי, זה הזמן המתאים לשמור את מצב האפליקציה שלא נשמר. |
כשהדף עובר מסטטוס פסיבי לסטטוס מוסתר, יכול להיות שהמשתמש לא יבצע איתו אינטראקציה שוב עד שהוא ייטען מחדש. המעבר למצב מוסתר הוא גם שינוי המצב האחרון
שהמפתחים יכולים לראות באופן מהימן (הדבר נכון במיוחד
בנייד, כי משתמשים יכולים לסגור כרטיסיות או את אפליקציית הדפדפן עצמה, והאירועים
המשמעות היא שצריך להתייחס למצב hidden כסיום הסביר של הסשן של המשתמש. במילים אחרות, לשמור את מצב האפליקציה שלא נשמר ולשלוח נתוני ניתוח שלא נשלחו. כמו כן, כדאי להפסיק לבצע עדכונים לממשק המשתמש (כי המשתמש לא יראה אותם), ולהפסיק משימות שהמשתמש לא רוצה שיפעלו ברקע. |
|
Frozen |
במצב frozen, משימות שאפשר להקפיא בתורנויות המשימות מושהות עד שההקפאה של הדף תוסר – ויכול להיות שההקפאה לא תוסר אף פעם (למשל, אם הדף נמחק). כלומר, כשהדף משתנה ממוסתר לקפוא, חשוב לעצור טיימרים או לנתק חיבורים, שעלולים להשפיע על כרטיסיות פתוחות אחרות באותו המקור או להשפיע על היכולת של הדפדפן להעביר את הדף למטמון לדף הקודם/הבא. במיוחד חשוב:
כדאי גם לשמור את כל מצב התצוגה הדינמי (למשל, מיקום הגלילה בתצוגת רשימה אינסופית) ב- אם הדף עובר ממצב קפוא בחזרה למוסתר, אפשר לפתוח מחדש חיבורים שנסגרו או להתחיל מחדש סקרים שעצרתם כשהדף הוקפא בהתחלה. |
Terminated |
בדרך כלל אין צורך לבצע פעולה כלשהי כשדף עובר למצב סגור. מכיוון שדפים שנטענים כתוצאה מפעולת משתמש תמיד עוברים במצב מוסתר לפני שהם עוברים למצב הסתיים, המצב מוסתר הוא המקום שבו צריך לבצע לוגיקה של סיום סשן (למשל שמירה על מצב האפליקציה ודיווח לניתוח נתונים). בנוסף (כפי שצוין בהמלצות למצב מוסתר), חשוב מאוד שהמפתחים יבינו שלא ניתן לזהות באופן מהימן את המעבר למצב הסיום במקרים רבים (במיוחד בנייד), ולכן מפתחים שתלויים באירועי סיום (למשל |
Discarded |
המפתחים לא יכולים לראות את המצב discarded בזמן שהדף נמחק. הסיבה לכך היא שבדרך כלל דפים נמחקים עקב אילוצים של משאבים, וברוב המקרים פשוט לא ניתן לבטל את ההקפאה של דף רק כדי לאפשר להפעלת סקריפט להגיב לאירוע מחיקה. לכן, כדאי להתכונן לאפשרות של ביטול השינוי ממוסתר לקפוא, ואז לבדוק את |
שוב, מכיוון שהאמינות והסדר של האירועים במחזור החיים לא מיושמים באופן עקבי בכל הדפדפנים, הדרך הקלה ביותר לפעול לפי העצות שבטבלה היא להשתמש ב-PageLifecycle.js.
ממשקי API מדור קודם למחזור חיים שיש להימנע מהם
במידת האפשר, כדאי להימנע מהאירועים הבאים.
אירוע ההסרה
מפתחים רבים מתייחסים לאירוע unload
כקריאה חוזרת מובטחת ומשתמשים בו כאות לסיום הסשן כדי לשמור את המצב ולשלוח נתוני ניתוח, אבל הדבר לא מהימן במיוחד, במיוחד בניידים. האירוע unload
לא מופעל בהרבה מצבים רגילים של ביטול טעינה, כולל סגירת כרטיסייה ממעבר הכרטיסיות בנייד או סגירת אפליקציית הדפדפן ממעבר האפליקציות.
לכן תמיד עדיף להסתמך על האירוע visibilitychange
כדי לקבוע מתי סשן מסתיים, ולחשיב את המצב הסמוי כזמן המהימן האחרון לשמירת נתוני אפליקציה ומשתמשים.
בנוסף, קיומו של הגורם המטפל באירועים רשום של unload
(באמצעות onunload
או addEventListener()
) עלול למנוע מהדפדפנים להוסיף דפים למטמון לדף הקודם/הבא כדי לאפשר טעינה מהירה יותר אחורה וקדימה.
בכל הדפדפנים המודרניים, מומלץ תמיד להשתמש באירוע pagehide
כדי לזהות אפשרויות של ביטול טעינת דפים (המכונה גם המצב terminated) במקום באירוע unload
. אם צריך תמיכה ב-Internet Explorer בגרסה 10 ומטה, כדאי לזהות את האירוע pagehide
ולהשתמש ב-unload
רק אם הדפדפן לא תומך ב-pagehide
:
const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
window.addEventListener(terminationEvent, (event) => {
// Note: if the browser is able to cache the page, `event.persisted`
// is `true`, and the state is frozen rather than terminated.
});
האירוע beforeunload
לאירוע beforeunload
יש בעיה דומה לבעיה של האירוע unload
, מאחר שבעבר נוכחות של אירוע beforeunload
יכלה למנוע מדפים לעמוד בדרישות לשמירה במטמון לדף הקודם/הבא. בדפדפנים מודרניים אין הגבלה כזו. עם זאת, דפדפנים מסוימים לא יפעילו את האירוע beforeunload
כצעד זהירות כשמנסים להעביר דף למטמון של 'הקודם'/'הבא', כלומר האירוע לא מהימן כאות לסיום הסשן.
בנוסף, בדפדפנים מסוימים (כולל Chrome) נדרשת אינטראקציה של משתמש בדף לפני שהאירוע beforeunload
יופעל, מה שמשפיע עוד יותר על האמינות שלו.
אחד ההבדלים בין beforeunload
ל-unload
הוא שיש שימושים לגיטימיים ב-beforeunload
. לדוגמה, כשרוצים להזהיר את המשתמש שיש לו שינויים שלא נשמרו, והם יאבדו אם הוא ימשיך לפרוק את הדף.
יש סיבות לגיטימיות לשימוש ב-beforeunload
, לכן מומלץ להוסיף רק מאזינים ל-beforeunload
כשלמשתמש יש שינויים שלא נשמרו, ואז להסיר אותם מיד אחרי שהם נשמרים.
במילים אחרות, אל תעשו את זה (כי הפעולה הזו מוסיפה מאזין beforeunload
ללא תנאי):
addEventListener('beforeunload', (event) => {
// A function that returns `true` if the page has unsaved changes.
if (pageHasUnsavedChanges()) {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
}
});
במקום זאת, צריך לעשות את הפעולות הבאות (כי הקוד הזה מוסיף את המאזין beforeunload
רק כשצריך, ומסיר אותו כשלא צריך):
const beforeUnloadListener = (event) => {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
};
// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
addEventListener('beforeunload', beforeUnloadListener);
});
// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
removeEventListener('beforeunload', beforeUnloadListener);
});
שאלות נפוצות
למה אין סטטוס 'טעינה'?
ב-Page Lifecycle API, המצבים מוגדרים כמצבים נפרדים ולא חופפים. מכיוון שדף יכול להיטען במצב פעיל, פסיבי או מוסתר, ויכול לשנות מצבים – או אפילו להסתיים – לפני שהוא מסיים את הטעינה, אין טעם להגדיר מצב טעינה נפרד בתוך הפרדיגמה הזו.
הדף שלי מבצע משימות חשובות גם כשהוא מוסתר. איך אפשר למנוע את הקפאתו או השמדתו?
יש הרבה סיבות לגיטימיות לכך שדפי אינטרנט לא צריכים להקפיא בזמן שהם פועלים במצב מוסתר. הדוגמה הברורה ביותר היא אפליקציה שמשמיעה מוזיקה.
יש גם מצבים שבהם יכול להיות מסוכן ל-Chrome לבטל דף, למשל אם הוא מכיל טופס עם קלט של משתמש שלא נשלח, או אם יש לו טיפול beforeunload
שמציג אזהרה כשהדף פורק.
בשלב הזה, Chrome יהיה שמרני בביטול דפים, ויבטל אותם רק אם הוא בטוח שהפעולה הזו לא תשפיע על המשתמשים. לדוגמה, דפים שנצפו בהם פעולות כלשהן מהפעולות הבאות בזמן שהם היו במצב מוסתר לא יוסרו, אלא אם יהיו הגבלות קיצוניות על המשאבים:
- הפעלת אודיו
- שימוש ב-WebRTC
- עדכון כותרת הטבלה או הסמל של הטבלה
- הצגת התראות
- שליחת התראות
כדי לקבל מידע על התכונות הנוכחיות של הרשימה שמשמשות לקביעת אם אפשר להקפיא או למחוק כרטיסייה בבטחה, אפשר לעיין במאמר שיטות ניתוח נתונים להקפאה ולמחיקה ב-Chrome.
מטמון לדף הקודם/הבא הוא מונח שמתאר אופטימיזציה של ניווט בחלק מהדפדפנים, שהופכת את השימוש בלחצנים 'הקודם' ו'הבא' למהיר יותר.
כשמשתמש עוזב דף, הדפדפנים האלה מקפיאים גרסה של הדף הזה כדי שניתן יהיה להמשיך אותו במהירות במקרה שהמשתמש יחזור לדף באמצעות הלחצנים 'הקודם' או 'הבא'. חשוב לזכור שהוספת גורם מטפל באירועים מסוג unload
מונעת את האפשרות לבצע את האופטימיזציה הזו.
מבחינה פונקציונלית, ההקפאה הזו זהה להקפאה שמתבצעת בדפדפנים כדי לחסוך בצריכת המעבד או הסוללה. לכן, היא נחשבת לחלק מסטטוס מחזור החיים frozen.
איך אפשר לשמור נתונים ב-IndexedDB אם אי אפשר להריץ ממשקי API אסינכררוניים במצבים 'קפוא' או 'הושעה'?
במצב קפוא או סגור, משימות שניתן להקפיא בתורי המשימות של דף מושעות. כלומר, לא ניתן להשתמש באופן מהימן בממשקי API אסינכרוניים ומבוססי קריאה חוזרת, כמו IndexedDB.
בעתיד נוסיף שיטה commit()
לאובייקטים מסוג IDBTransaction
, שתאפשר למפתחים לבצע טרנזקציות לכתיבה בלבד, ללא צורך בקריאות חזרה (callbacks). במילים אחרות, אם המפתח רק כותב נתונים ל-IndexedDB ולא מבצע עסקה מורכבת שמכילה קריאות וכתיבה, השיטה commit()
תוכל להסתיים לפני שתורנויות המשימות יושהו (בהנחה שמסד הנתונים של IndexedDB כבר פתוח).
עם זאת, למפתחים שיש להם קוד שצריך לפעול כבר היום יש שתי אפשרויות:
- שימוש ב-Session Storage: Session Storage הוא סנכרוני ונשמר גם אחרי שמחרימים דפים.
- משתמשים ב-IndexedDB מ-service worker: קובץ שירות (service worker) יכול לאחסן נתונים ב-IndexedDB אחרי שהדף נסגר או נמחק. אפשר לשלוח נתונים ל-service worker דרך
postMessage()
במעקב האירועיםfreeze
אוpagehide
, וה-service worker יכול לטפל בשמירת הנתונים.
בדיקת האפליקציה במצב 'קפוא' או 'נמחק'
כדי לבדוק איך האפליקציה מתנהגת במצבים 'הקפאה' ו'מחיקה', אפשר להיכנס לדף chrome://discards
כדי להקפיא או למחוק את הכרטיסיות הפתוחות.
כך תוכלו לוודא שהדף מטפל בצורה נכונה באירועים freeze
ו-resume
, וגם בדגל document.wasDiscarded
כשדפים נטענים מחדש אחרי שהם נמחקים.
סיכום
מפתחים שרוצים לכבד את משאבי המערכת של המכשירים של המשתמשים שלהם צריכים לפתח את האפליקציות שלהם תוך התחשבות במצבים של מחזור החיים של הדף. חשוב מאוד שדפי אינטרנט לא צורכים משאבי מערכת מוגזמים במצבים שהמשתמשים לא מצפים להם.
ככל שיותר מפתחים יתחילו להטמיע את ממשקי ה-API החדשים של מחזור החיים של דפים, כך יהיה בטוח יותר לדפדפנים להקפיא ולמחוק דפים שלא בשימוש. המשמעות היא שהדפדפנים צורכים פחות זיכרון, מעבד (CPU), סוללה ומשאבי רשת, וזה יתרון למשתמשים.