תמיכה בדפדפנים
דפדפנים מודרניים לפעמים משעים דפים או מוחקים אותם לחלוטין כאשר משאבי המערכת מוגבלים. בעתיד, הדפדפנים ירצו לעשות זאת באופן יזום כדי לצמצם את צריכת החשמל והזיכרון. Page Lifecycle API מספק וו hooks של מחזור חיים, כדי שהדפים יוכלו לטפל בבטחה בהתערבויות האלה בדפדפן בלי להשפיע על חוויית המשתמש. כדאי לעיין ב-API כדי לבדוק אם כדאי להטמיע את התכונות האלה באפליקציה.
רקע
מחזור החיים של אפליקציות הוא אחד האמצעים העיקריים שבהם מערכות הפעלה מודרניות מנהלות את המשאבים. ב-Android, ב-iOS ובגרסאות האחרונות של Windows, מערכת ההפעלה יכולה להפעיל ולהפסיק אפליקציות בכל שלב. כך הפלטפורמות האלה יכולות לייעל את המשאבים ולחלק אותם מחדש באופן שמניב את התועלת הרבה ביותר למשתמש.
באינטרנט, לא היה בעבר מחזור חיים כזה, והאפליקציות יכולות להמשיך לפעול ללא הגבלת זמן. כשמפעילים מספר גדול של דפי אינטרנט, יכול להיות שיהיה ביקוש יתר על משאבי מערכת קריטיים כמו זיכרון, מעבד (CPU), סוללה ורשת, וכתוצאה מכך חוויית המשתמש תהיה גרועה.
כבר זמן רב יש בפלטפורמת האינטרנט אירועים שקשורים למצבים במחזור החיים, כמו load
, unload
ו-visibilitychange
. עם זאת, האירועים האלה מאפשרים למפתחים להגיב רק לשינויים במצבים במחזור החיים שהמשתמשים יזמו. כדי שהאינטרנט יפעל באופן מהימן במכשירים עם חשמל נמוך (ויהיו יותר מוּדעוּת למשאבים באופן כללי בכל הפלטפורמות), הדפדפנים צריכים דרך יזום והקצאה מחדש של משאבי המערכת.
למעשה, דפדפנים כבר נוקטים פעולות פעילות לחיסכון במשאבים בדפים בכרטיסיות ברקע, ודפדפנים רבים (במיוחד Chrome) רוצים להרחיב את הפעולות האלה כדי לצמצם את טביעת הרגל הכוללת שלהם במשאבים.
הבעיה היא שלמפתחים אין דרך להתכונן לסוגים כאלה של התערבות מצד המערכת, או אפילו לדעת שהם מתרחשים. כלומר, הדפדפנים צריכים לפעול באופן שמרני, אחרת הם עלולים לגרום לשיבושים בדפי אינטרנט.
Page Lifecycle API מנסה לפתור את הבעיה הזו באמצעות:
- השקה וסטנדרטיזציה של המושג 'מצבים במחזור החיים' באינטרנט.
- הגדרת מצבים חדשים שמנוהלים על ידי המערכת ומאפשרים לדפדפנים להגביל את המשאבים שיכולים להיות נצרכים על ידי כרטיסיות מוסתרות או לא פעילות.
- יצירת ממשקי API ואירועים חדשים שמאפשרים למפתחי אתרים להגיב למעבר למצבים החדשים ביוזמת המערכת ומהם.
הפתרון הזה מספק את יכולת החיזוי שמפתחי אתרים צריכים לפתח כדי לפתח אפליקציות עמידות להתערבות במערכת, ומאפשר לדפדפנים לבצע אופטימיזציה אגרסיבית יותר של משאבי המערכת, ובסופו של דבר להפיק תועלת מכל משתמשי האינטרנט.
בהמשך הפוסט נסביר על התכונות החדשות של מחזור החיים של הדף ונראה איך הן קשורות לכל המצבים והאירועים הקיימים בפלטפורמת האינטרנט. בנוסף, נספק המלצות ושיטות מומלצות לגבי סוגי העבודה שמפתחים צריכים לבצע (ולא לבצע) בכל מצב.
סקירה כללית על המצבים והאירועים במחזור החיים של דפים
כל המצבים של מחזור החיים של הדף הם נפרדים ומנוגדים זה לזה, כלומר דף יכול להיות רק במצב אחד בכל פעם. בנוסף, בדרך כלל אפשר לראות את רוב השינויים במצב של מחזור החיים של הדף באמצעות אירועי DOM (החרגות מפורטות בהמלצות למפתחים לכל מצב).
הדרך הקלה ביותר להסביר את המצבים במחזור החיים של הדף, וגם את האירועים שמסמנים את המעברים ביניהם, היא באמצעות תרשים:
מדינות
בטבלה הבאה מוסבר כל מצב בפירוט. בנוסף, מפורטים המצבים האפשריים שיכולים להתרחש לפני ואחרי, וגם האירועים שמפתחים יכולים להשתמש בהם כדי לעקוב אחרי השינויים.
מדינה | תיאור |
---|---|
פעיל |
דף נמצא במצב פעיל אם הוא גלוי ורק צריך להתמקד בקלט.
מצבים קודמים אפשריים: |
פסיבי |
דף במצב פסיבי אם הוא גלוי ואין בו פוקוס קלט.
מצבים קודמים אפשריים:
המצבים הבאים אפשריים: |
סמויה |
דף נמצא בסטטוס מוסתר אם הוא לא גלוי (ולא הוקפא, הושלך או הופסק).
מצבים קודמים אפשריים:
המצבים האפשריים הבאים: |
קפוא |
במצב קפוא, הדפדפן משעה את הביצוע של
משימות שניתנות להקפאה
משימות ב
תורי המשימות של הדף עד לביטול הקפאת הדף. המשמעות היא שדברים כמו שעונים של JavaScript וקריאות חוזרות (callbacks) של אחזור לא פועלים. משימות שכבר פועלות יכולות להסתיים (החשובה שבהן היא קריאת החזרה (callback) של דפדפנים מקפיאים דפים כדי לחסוך בשימוש במעבד, בסוללה ובנתונים. הם עושים זאת גם כדי לאפשר ניווט מהיר יותר לאחור או קדימה, וכך למנוע צורך בטעינה מחדש מלאה של הדף.
מצבים קודמים אפשריים:
המצבים הבאים אפשריים: |
Terminated |
הדף נמצא במצב סגור אחרי שהטעינה שלו התחילה, והוא נוקה מהזיכרון על ידי הדפדפן. אי אפשר להתחיל משימות חדשות במצב הזה, ומשימות שעוד לא בוצעו עלולים להימחק אם הן נמשכות יותר מדי זמן.
מצבים קודמים אפשריים:
המצבים הבאים האפשריים: |
נמחקה |
הדף במצב discarded (נמחק) כאשר הדפדפן מבטל את הטעינה שלו כדי לשמור על משאבים. אי אפשר להריץ משימות, אירועים חוזרים או JavaScript מכל סוג שהוא במצב הזה, כי בדרך כלל השלכת אירועים מתרחשת במצב של אילוצי משאבים, שבהם אי אפשר להפעיל תהליכים חדשים. בסטטוס discarded, הכרטיסייה עצמה (כולל כותרת הכרטיסייה וסמל הדף) בדרך כלל גלויה למשתמש, גם אם הדף לא מופיע.
מצבים קודמים אפשריים:
המדינות הבאות האפשריות: |
אירועים
הדפדפנים שולחים הרבה אירועים, אבל רק חלק קטן מהם מאותת על שינוי אפשרי במצב של מחזור החיים של הדף. בטבלה הבאה מפורטים כל האירועים שקשורים למחזור החיים, ומפורטות המצבים שהם יכולים לעבור אליהם ומהם.
שם | פרטים |
---|---|
focus
|
רכיב DOM קיבל את המיקוד.
הערה: אירוע
מצבים קודמים אפשריים:
המצבים הנוכחיים האפשריים: |
blur
|
רכיב DOM איבד את המיקוד.
הערה: אירוע
הסטטוסים הקודמים האפשריים:
המצבים הנוכחיים האפשריים: |
visibilitychange
|
הערך של השדה |
freeze
*
|
הדף הוקפא עכשיו. כל משימה שניתנת להקפאה בדופים של תור המשימות לא תתחיל.
הסטטוסים הקודמים האפשריים:
המצבים הנוכחיים האפשריים: |
resume
*
|
הדפדפן המשיך בדף מקופא.
מצבים קודמים אפשריים:
מצבים אפשריים נוכחיים: |
pageshow
|
מתבצע מעבר לרשומה בהיסטוריית הסשנים. יכול להיות שמדובר בטעינה של דף חדש לגמרי או בדף שנלקח ממטמון לדף הקודם/הבא. אם הדף נלקח מהמטמון לדף הקודם/הבא, הערך של המאפיין |
pagehide
|
הנתונים מגיעים מהרשומה בהיסטוריית הסשנים. אם המשתמש מנווט לדף אחר והדפדפן יכול להוסיף את הדף הנוכחי למטמון של דפים קודמים/באים כדי לעשות בו שימוש חוזר מאוחר יותר, הערך של המאפיין
הסטטוסים הקודמים האפשריים:
מצבים אפשריים נוכחיים: |
beforeunload
|
הטעינה של החלון, המסמך והמשאבים שלו עומדים להתבצע. המסמך עדיין גלוי והאירוע עדיין ניתן לביטול בשלב הזה.
חשוב: צריך להשתמש באירוע
הסטטוסים הקודמים האפשריים:
הסטטוסים האפשריים הנוכחיים: |
unload
|
מתבצעת טעינה של הדף.
אזהרה: אף פעם לא מומלץ להשתמש באירוע
הסטטוסים הקודמים האפשריים:
הסטטוסים האפשריים הנוכחיים: |
* מציין אירוע חדש שהוגדר על ידי ה-API של מחזור החיים של הדף
תכונות חדשות שנוספו בגרסה 68 של Chrome
בתרשים הקודם מוצגות שתי סטטוסים שהמערכת מפעילה ולא המשתמש: קפוא ומושלך. כפי שצוין קודם, דפדפנים כבר מקפיאים מדי פעם כרטיסיות מוסתרות ומבטלים אותן (לפי שיקול דעתם), אבל למפתחים אין דרך לדעת מתי זה קורה.
ב-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';
};
לעומת זאת, אפשר לזהות את המצבים frozen ו-terminated רק ב-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 הוא לרוב השינוי האחרון בסטטוס שאפשר לראות בצורה מהימנה (במיוחד בנייד, כי משתמשים יכולים לסגור כרטיסיות או את אפליקציית הדפדפן עצמה, ובמקרים כאלה האירועים המשמעות היא שצריך להתייחס למצב hidden כסיום הסביר של הסשן של המשתמש. במילים אחרות, לשמור את מצב האפליקציה שלא נשמר ולשלוח נתוני ניתוח שלא נשלחו. כמו כן, כדאי להפסיק לבצע עדכונים לממשק המשתמש (כי המשתמש לא יראה אותם), ולהפסיק משימות שהמשתמש לא רוצה שיפעלו ברקע. |
|
Frozen |
במצב frozen, משימות שאפשר להקפיא בתורנויות המשימות מושהות עד שההקפאה של הדף תוסר – ויכול להיות שההקפאה לא תוסר אף פעם (למשל, אם הדף נמחק). כלומר, כשהדף עובר מסטטוס מוסתר לסטטוס קפוא, חובה לעצור את כל הטיימרים או לבטל את כל החיבורים שעשויים להשפיע על כרטיסיות פתוחות אחרות באותו מקור, או על היכולת של הדפדפן להעביר את הדף ל מטמון של דפים קודמים/לאחור. במיוחד חשוב:
כדאי גם לשמור את כל מצב התצוגה הדינמי (למשל, מיקום הגלילה בתצוגת רשימה אינסופית) ב- אם הדף עובר מקפוא למוסתר, תוכלו לפתוח מחדש את כל החיבורים הסגורים או להפעיל מחדש את כל הסקרים שעצרתם כשהדף קפא בהתחלה. |
Terminated |
בדרך כלל אין צורך לבצע פעולה כלשהי כשדף עובר למצב הושעה. מאחר שדפים שמנוהלים לטעינה מחדש כתוצאה מפעולה של משתמש תמיד עוברים דרך המצב hidden לפני שהם נכנסים למצב terminated, המצב hidden הוא המקום שבו צריך לבצע את הלוגיקה של סיום הסשן (למשל, שמירת מצב האפליקציה ודוחות ל-Analytics). בנוסף (כפי שצוין בהמלצות למצב מוסתר), חשוב מאוד שהמפתחים יבינו שלא ניתן לזהות באופן מהימן את המעבר למצב הסיום במקרים רבים (במיוחד בנייד), ולכן מפתחים שתלויים באירועי סיום (למשל |
Discarded |
המפתחים לא יכולים לראות את המצב discarded בזמן שהדף נמחק. הסיבה לכך היא שבדרך כלל דפים נמחקים ממגבלות משאבים, וברוב המקרים לא ניתן לבטל את ההקפאה של דף רק כדי לאפשר לסקריפט לפעול בתגובה לאירוע מחיקה. כתוצאה מכך, כדאי להתכונן למחיקה של השינוי ממוסתר לקפוא, ואז אפשר להגיב לשחזור של דף שנמחק בזמן הטעינה של דף על ידי בדיקת
|
שוב, מכיוון שההטמעה של מהימנות וסדר האירועים במחזור החיים לא עקבית בכל הדפדפנים, הדרך הקלה ביותר לפעול בהתאם להמלצות בטבלה היא להשתמש ב-PageLifecycle.js.
ממשקי API מדור קודם של מחזור חיים שצריך להימנע מהם
במידת האפשר, כדאי להימנע מהאירועים הבאים.
האירוע 'הסרת הנתונים שנטענו'
מפתחים רבים מתייחסים לאירוע unload
כקריאה חוזרת מובטחת ומשתמשים בו כאות לסיום הסשן כדי לשמור את המצב ולשלוח נתוני ניתוח, אבל הדבר לא מהימן במיוחד, במיוחד בניידים. האירוע unload
לא מופעל במצבים רבים טיפוסיים של הסרת תוכן, כולל סגירת כרטיסייה מהחלפת הכרטיסיות בנייד או סגירה של אפליקציית הדפדפן במעבר בין אפליקציות.
לכן, תמיד עדיף להסתמך על האירוע visibilitychange
כדי לקבוע מתי הסשן מסתיים, ולחשוב על המצב המוסתר בתור הזמן האחרון המהימן לשמירת נתוני האפליקציה והמשתמשים.
בנוסף, קיומו של הגורם המטפל באירועים רשום של unload
(באמצעות onunload
או addEventListener()
) עלול למנוע מהדפדפנים להוסיף דפים למטמון לדף הקודם/הבא כדי לאפשר טעינה מהירה יותר אחורה וקדימה.
בכל הדפדפנים המתקדמים מומלץ תמיד להשתמש באירוע pagehide
כדי לזהות העלאות אפשריות של דפים (שנקראות גם המצב הסתיים) ולא באירוע 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);
});
שאלות נפוצות
למה אין סטטוס 'טעינה'?
ה-API של מחזור החיים של הדף מגדיר מצבים בדידים ובלעדיים. מכיוון שדף יכול להיטען במצב פעיל, פסיבי או מוסתר, ויכול לשנות מצבים – או אפילו להסתיים – לפני שהוא מסיים את הטעינה, אין טעם להגדיר מצב טעינה נפרד בתוך הפרדיגמה הזו.
הדף שלי מבצע משימות חשובות גם כשהוא מוסתר. איך אפשר למנוע את הקפאתו או השמדתו?
יש הרבה סיבות לגיטימיות לא להקפיא דפי אינטרנט כשהם במצב סמוי. הדוגמה הברורה ביותר היא אפליקציה שמשמיעה מוזיקה.
יש גם מצבים שבהם יכול להיות מסוכן ל-Chrome לבטל דף, למשל אם הוא מכיל טופס עם קלט של משתמש שלא נשלח, או אם יש לו טיפול beforeunload
שמציג אזהרה כשהדף פורק.
בשלב הזה, Chrome יהיה שמרני בביטול דפים, ויבטל אותם רק אם הוא בטוח שהפעולה הזו לא תשפיע על המשתמשים. לדוגמה, דפים שנצפו בהם פעולות כלשהן מהפעולות הבאות בזמן שהם היו במצב מוסתר לא יוסרו, אלא אם יהיו הגבלות קיצוניות על המשאבים:
- הפעלת אודיו
- שימוש ב-WebRTC
- עדכון כותרת הטבלה או הסמל של הטבלה
- הצגת התראות
- שליחת התראות
כדי לקבל מידע על התכונות הנוכחיות של הרשימה שמשמשות לקביעת אם אפשר להקפיא או למחוק כרטיסייה בבטחה, אפשר לעיין במאמר שיטות ניתוח נתונים להקפאה ולמחיקה ב-Chrome.
מטמון לדף הקודם/הבא הוא מונח שמתאר אופטימיזציה של הניווט שחלק מהדפדפנים מטמיעים, כדי שהשימוש בלחצני 'הקודם' ו'הבא' יהיה מהיר יותר.
כשמשתמש עוזב דף, הדפדפנים האלה מקפיאים גרסה של הדף הזה כדי שניתן יהיה להמשיך אותו במהירות במקרה שהמשתמש יחזור לדף באמצעות הלחצנים 'הקודם' או 'הבא'. חשוב לזכור שהוספת גורם מטפל באירועים מסוג unload
מונעת את האפשרות לבצע את האופטימיזציה הזו.
מבחינה פונקציונלית, ההקפאה הזו זהה להקפאה שמתבצעת בדפדפנים כדי לחסוך בצריכת המעבד או הסוללה. לכן, היא נחשבת לחלק מסטטוס מחזור החיים frozen.
אם אי אפשר להריץ ממשקי API אסינכרוניים במצב של 'קפוא' או של 'הסתיים', איך אפשר לשמור את הנתונים ב-IndexedDB?
בסטטוסים 'מושהה' ו'הושעה', משימות שאפשר להשהות בתורנויות המשימות של הדף מושהות. המשמעות היא שאי אפשר להשתמש באופן מהימן בממשקי API אסינכררוניים ומבוססי קריאה חוזרת (callback), כמו 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), סוללה ומשאבי רשת, וזה יתרון למשתמשים.