Browser Support
דפדפנים מודרניים לפעמים משעים דפים או מסירים אותם לגמרי כשמשאבי המערכת מוגבלים. בעתיד, הדפדפנים ירצו לעשות את זה באופן יזום, כדי לצרוך פחות חשמל וזיכרון. Page Lifecycle API מספק נקודות עצירה במחזור החיים, כך שהדפים יכולים לטפל בבטחה בהתערבויות האלה של הדפדפן בלי להשפיע על חוויית המשתמש. כדאי לעיין ב-API כדי להבין אם כדאי להטמיע את התכונות האלה באפליקציה.
רקע
מחזור החיים של האפליקציה הוא דרך חשובה שבה מערכות הפעלה מודרניות מנהלות משאבים. ב-Android, ב-iOS ובגרסאות עדכניות של Windows, מערכת ההפעלה יכולה להפעיל ולהפסיק אפליקציות בכל שלב. כך הפלטפורמות האלה יכולות לייעל את השימוש במשאבים ולהקצות אותם מחדש במקומות שבהם הם מועילים למשתמשים בצורה הכי טובה.
באינטרנט, היסטורית לא היה מחזור חיים כזה, ואפשר היה להשאיר אפליקציות פעילות ללא הגבלת זמן. כשמספר גדול של דפי אינטרנט פועלים, יכול להיות שיהיה ביקוש יתר למשאבי מערכת קריטיים כמו זיכרון, מעבד (CPU), סוללה ורשת, מה שיוביל לחוויית משתמש גרועה.
לפלטפורמת האינטרנט יש כבר הרבה זמן אירועים שקשורים למצבי מחזור חיים – כמו load, unload ו-visibilitychange – אבל האירועים האלה מאפשרים למפתחים רק להגיב לשינויים במצב מחזור החיים שמתחילים על ידי המשתמש. כדי שהאינטרנט יפעל בצורה מהימנה במכשירים עם צריכת חשמל נמוכה (וכדי שבאופן כללי יהיה שימוש יעיל יותר במשאבים בכל הפלטפורמות), דפדפנים צריכים דרך להקצות מחדש משאבי מערכת באופן יזום.
למעשה, דפדפנים כיום כבר נוקטים אמצעים פעילים לחיסכון במשאבים בדפים בכרטיסיות ברקע, ודפדפנים רבים (במיוחד Chrome) רוצים לעשות הרבה יותר מזה – כדי לצמצם את טביעת הרגל הכוללת של המשאבים שלהם.
הבעיה היא שלמפתחים אין דרך להתכונן לסוגים האלה של התערבויות שמתחילות על ידי המערכת, או אפילו לדעת שהן מתרחשות. כלומר, הדפדפנים צריכים להיות שמרניים או שהם עלולים לגרום לשיבוש בדפי אינטרנט.
Page Lifecycle API מנסה לפתור את הבעיה הזו באמצעות:
- הצגה של המושג 'מצבי מחזור חיים' באינטרנט והפיכתו לסטנדרט.
- הגדרת מצבים חדשים שמופעלים על ידי המערכת ומאפשרים לדפדפנים להגביל את המשאבים שכרטיסיות מוסתרות או לא פעילות יכולות לצרוך.
- יצירת ממשקי API ואירועים חדשים שמאפשרים למפתחי אתרים להגיב למעברים אל המצבים החדשים האלה וממצבים כאלה, שהמערכת יזמה.
הפתרון הזה מספק למפתחי אתרים את היכולת לצפות מראש את התוצאות שהם צריכים כדי לבנות אפליקציות עמידות להתערבויות של המערכת, והוא מאפשר לדפדפנים לבצע אופטימיזציה של משאבי המערכת בצורה אגרסיבית יותר, ובסופו של דבר להועיל לכל משתמשי האינטרנט.
בהמשך הפוסט נציג את התכונות החדשות של מחזור החיים של הדף ונבדוק איך הן קשורות לכל המצבים והאירועים הקיימים בפלטפורמת האינטרנט. הוא גם יציע המלצות ושיטות מומלצות לגבי סוגי העבודה שמפתחים צריכים (ולא צריכים) לבצע בכל מצב.
סקירה כללית של מצבים ואירועים במחזור החיים של דף
כל המצבים של מחזור החיים של הדף הם נפרדים ומוציאים זה את זה, כלומר דף יכול להיות רק במצב אחד בכל רגע נתון. בדרך כלל אפשר לראות את רוב השינויים במצב מחזור החיים של דף באמצעות אירועי DOM (במאמר המלצות למפתחים לכל מצב מפורטים היוצאים מן הכלל).
הדרך הכי קלה להסביר את מצבי מחזור החיים של הדף – וגם את האירועים שמסמלים מעברים ביניהם – היא באמצעות דיאגרמה:
מדינות
בטבלה הבאה מוסבר כל סטטוס בפירוט. בנוסף, מפורטים בו המצבים האפשריים שיכולים להיות לפני ואחרי, וגם האירועים שמפתחים יכולים להשתמש בהם כדי לעקוב אחרי שינויים.
| מדינה | תיאור |
|---|---|
| פעיל | דף נמצא במצב פעיל אם הוא גלוי והמיקוד של הקלט נמצא בו. מצבים קודמים אפשריים: |
| פסיבי | דף נמצא במצב פסיבי אם הוא גלוי ואין לו מיקוד קלט. מצבים קודמים אפשריים: מצבים אפשריים הבאים: |
| מוסתר | דף נמצא במצב מוסתר אם הוא לא גלוי (ולא הוקפא, נמחק או נסגר). מצבים קודמים אפשריים: מצבים אפשריים בהמשך: |
| Frozen | במצב frozen, הדפדפן משעה את הביצוע של משימות freezable ב תורי המשימות של הדף עד שהדף מופשר. המשמעות היא שדברים כמו טיימרים של JavaScript וקריאות חוזרות (callback) של אחזור לא פועלים. משימות שכבר פועלות יכולות להסתיים (הכי חשוב, הקריאה החוזרת הדפדפנים מקפיאים דפים כדי לחסוך בשימוש במעבד, בסוללה ובנתונים. הם גם עושים את זה כדי לאפשר ניווט מהיר יותר בין הדפים הקודם והבא, וכך לא צריך לטעון מחדש את הדף באופן מלא. מצבים קודמים אפשריים: המצבים הבאים האפשריים: |
| הסתיים | דף נמצא במצב הסתיים ברגע שהדפדפן מתחיל להסיר את הנתונים שנטענו ולנקות אותו מהזיכרון. לא ניתן להתחיל משימות חדשות במצב הזה, ומשימות שנמצאות בתהליך עלולות להיפסק אם הן פועלות יותר מדי זמן. מצבים קודמים אפשריים: הסטטוסים הבאים האפשריים: |
| נמחקו | דף נמצא במצב discarded (הוצאה מהזיכרון) כשהדפדפן מסיר אותו מהזיכרון כדי לחסוך במשאבים. במצב הזה אי אפשר להריץ משימות, קריאות חוזרות (callback) לאירועים או JavaScript מכל סוג, כי בדרך כלל מתבצעות השמטות בגלל מגבלות משאבים, שבהן אי אפשר להתחיל תהליכים חדשים. במצב discarded, הכרטיסייה עצמה (כולל הכותרת והסמל שלה) בדרך כלל גלויה למשתמש, גם אם הדף נעלם. מצבים קודמים אפשריים: הסטטוסים הבאים האפשריים: |
אירועים
הדפדפנים שולחים הרבה אירועים, אבל רק חלק קטן מהם מצביע על שינוי אפשרי במצב מחזור החיים של הדף. בטבלה הבאה מפורטים כל האירועים שקשורים למחזור החיים, ומוצגים המצבים שמהם הם יכולים לעבור ואליהם הם יכולים לעבור.
| שם | פרטים |
|---|---|
focus | רכיב DOM קיבל מיקוד. הערה: אירוע מצבים קודמים אפשריים: הסטטוסים האפשריים: |
blur | רכיב DOM איבד את המיקוד. הערה: אירוע סטטוסים קודמים אפשריים: המצבים הנוכחיים האפשריים: |
visibilitychange | הערך של |
freeze * | הדף הוקפא. משימות freezable בתורי המשימות של הדף לא יתחילו. הסטטוסים הקודמים האפשריים: הסטטוסים הנוכחיים האפשריים: |
resume * | הדפדפן חידש דף קפוא. מצבים קודמים אפשריים: מצבים נוכחיים אפשריים: |
pageshow | מתבצעת מעבר אל רשומה בהיסטוריית הסשנים. יכול להיות שמדובר בטעינה של דף חדש לגמרי או בדף שנלקח מהמטמון לדף הקודם/הבא. אם הדף נלקח מהמטמון לדף הקודם/הבא, המאפיין |
pagehide | המעבר מתבצע מתוך רשומה בהיסטוריית הסשנים. אם המשתמש מנווט לדף אחר והדפדפן יכול להוסיף את הדף הנוכחי למטמון לדף הקודם/הבא כדי לעשות בו שימוש חוזר בהמשך, הערך של המאפיין הסטטוסים הקודמים האפשריים: מצבים נוכחיים אפשריים: |
beforeunload | החלון, המסמך והמשאבים שלו עומדים להיסגר. המסמך עדיין גלוי והאירוע עדיין ניתן לביטול בשלב הזה. חשוב: צריך להשתמש באירוע הסטטוסים הקודמים האפשריים: הסטטוסים האפשריים: |
unload | הדף עובר ביטול טעינה. אזהרה: לא מומלץ להשתמש באירוע הסטטוסים הקודמים האפשריים: הסטטוסים הנוכחיים האפשריים: |
* מציין אירוע חדש שהוגדר על ידי Page Lifecycle API
תכונות חדשות שנוספו בגרסה 68 של Chrome
בתרשים הקודם מוצגים שני מצבים שהמערכת יוזמת ולא המשתמש: frozen ו-discarded. כמו שציינו קודם, דפדפנים היום כבר קופאים מדי פעם ומשליכים כרטיסיות מוסתרות (לפי שיקול דעתם), אבל למפתחים אין דרך לדעת מתי זה קורה.
ב-Chrome 68, מפתחים יכולים עכשיו לראות מתי כרטיסייה מוסתרת מוקפאת ומתי היא מבוטלת ההקפאה שלה. לשם כך הם צריכים להאזין לאירועים freeze ו-resume ב-document.
document.addEventListener('freeze', (event) => { // The page is now frozen. }); document.addEventListener('resume', (event) => { // The page has been unfrozen. }); החל מ-Chrome 68, האובייקט document כולל עכשיו את המאפיין wasDiscarded ב-Chrome למחשב (התמיכה ב-Android נמצאת במעקב בבעיה הזו). כדי לקבוע אם דף נמחק בזמן שהוא היה בכרטיסייה מוסתרת, אפשר לבדוק את הערך של המאפיין הזה בזמן טעינת הדף (הערה: צריך לטעון מחדש דפים שנמחקו כדי להשתמש בהם שוב).
if (document.wasDiscarded) { // Page was previously discarded by the browser while in a hidden tab. } לקבלת עצות לגבי הפעולות החשובות שצריך לבצע באירועים freeze ו-resume, וגם לגבי אופן הטיפול בדפים שמוסרים וההכנה לכך, אפשר לעיין בהמלצות למפתחים לגבי כל מצב.
בקטעים הבאים מופיעה סקירה כללית של האופן שבו התכונות החדשות האלה משתלבות במצבים ובאירועים הקיימים של פלטפורמת האינטרנט.
איך בודקים את מצבי מחזור החיים של הדף בקוד
במצבים active, passive ו-hidden אפשר להריץ קוד 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(). - הפונקציה מקבלת את המצב הבא, ואם יש שינוי, היא מתעדת את השינויים במצב במסוף.
- הוספה של capturing event listeners לכל אירועי מחזור החיים הנדרשים, שבתורם קוראים ל-
logStateChange(), ומעבירים את המצב הבא.
חשוב לשים לב שבקוד, כל פונקציות event listener מתווספות ל-window וכולן מעבירות את {capture: true}. יכולות להיות לכך כמה סיבות:
- לא לכל האירועים במחזור החיים של הדף יש יעד זהה.
pagehideו-pageshowמופעלים ב-window,visibilitychange,freezeו-resumeמופעלים ב-document,focusו-blurמופעלים ברכיבי ה-DOM המתאימים. - רוב האירועים האלה לא מתפשטים, מה שאומר שאי אפשר להוסיף פונקציות event listener שלא לוכדות לאלמנט אב משותף ולצפות בכולם.
- שלב הלכידה מתבצע לפני שלבי היעד או הבועה, ולכן הוספת מאזינים לשלב הזה עוזרת לוודא שהם יפעלו לפני שקוד אחר יוכל לבטל אותם.
המלצות למפתחים לכל מצב
חשוב למפתחים להבין את מצבי מחזור החיים של הדף ולדעת איך לעקוב אחריהם בקוד, כי סוג העבודה שצריך (ושלא צריך) לבצע תלוי במידה רבה במצב של הדף.
לדוגמה, אין היגיון בהצגת הודעה זמנית למשתמש אם הדף במצב מוסתר. הדוגמה הזו די ברורה, אבל יש המלצות אחרות שלא כל כך ברורות שכדאי לפרט.
| מדינה | המלצות למפתחים |
|---|---|
Active | המצב פעיל הוא השלב הכי חשוב למשתמש, ולכן זה השלב הכי חשוב שבו הדף צריך להיות רספונסיבי לקלט של המשתמש. צריך להוריד את העדיפות של כל עבודה שאינה קשורה לממשק המשתמש ועלולה לחסום את ה-thread הראשי, ולהעביר אותה אל תקופות של חוסר פעילות או להעביר אותה אל web worker. |
Passive | במצב passive המשתמש לא מקיים אינטראקציה עם הדף, אבל הוא עדיין יכול לראות אותו. כלומר, עדכונים והנפשות בממשק המשתמש עדיין צריכים להיות חלקים, אבל התזמון של העדכונים האלה פחות קריטי. כשהדף משתנה מפעיל לסביל, זה הזמן המתאים לשמור את מצב האפליקציה שלא נשמר. |
| כשדף משתנה מפסיבי למוסתר, יכול להיות שהמשתמש לא יקיים איתו אינטראקציה שוב עד שהוא ייטען מחדש. המעבר למצב מוסתר הוא גם לרוב שינוי המצב האחרון שאפשר לצפות בו באופן מהימן על ידי מפתחים (זה נכון במיוחד בנייד, כי משתמשים יכולים לסגור כרטיסיות או את אפליקציית הדפדפן עצמה, והאירועים המשמעות היא שצריך להתייחס למצב מוסתר כסיום הסביר של הסשן של המשתמש. במילים אחרות, צריך לשמור את מצב האפליקציה שלא נשמר ולשלוח את נתוני הניתוח שלא נשלחו. כדאי גם להפסיק לבצע עדכונים בממשק המשתמש (כי המשתמש לא יראה אותם), ולהפסיק כל משימה שהמשתמש לא רוצה שתפעל ברקע. | |
Frozen | במצב הקפאה, משימות שניתנות להקפאה ב תורי המשימות מושהות עד שההקפאה של הדף מבוטלת – מה שיכול להיות שלא יקרה לעולם (למשל, אם הדף נמחק). כלומר, כשהדף משתנה ממוסתר למוקפא, חשוב להפסיק את כל הטיימרים או לנתק את כל החיבורים שאם הם יוקפאו, הם עלולים להשפיע על כרטיסיות פתוחות אחרות באותו מקור, או להשפיע על היכולת של הדפדפן להכניס את הדף ל מטמון של חזרה/קדימה. חשוב במיוחד:
כדאי גם לשמור את מצב התצוגה הדינמי (למשל, מיקום הגלילה בתצוגת רשימה אינסופית) ב- אם הדף עובר ממצב מוקפא בחזרה למצב מוסתר, אפשר לפתוח מחדש חיבורים סגורים או להפעיל מחדש סקרים שהפסקתם כשהדף הוקפא בהתחלה. |
Terminated | בדרך כלל לא צריך לבצע שום פעולה כשדף עובר למצב terminated. מכיוון שדפים שנפרקים כתוצאה מפעולת משתמש תמיד עוברים למצב מוסתר לפני שהם עוברים למצב הופסק, במצב מוסתר צריך לבצע את הלוגיקה של סיום הסשן (למשל, שמירת מצב האפליקציה ודיווח ל-Analytics). בנוסף (כפי שצוין בהמלצות לגבי מצב מוסתר), חשוב מאוד למפתחים להבין שבמקרים רבים (במיוחד בנייד) אי אפשר לזהות באופן מהימן את המעבר למצב terminated, ולכן מפתחים שמסתמכים על אירועי סיום (למשל |
Discarded | מפתחים לא יכולים לראות את המצב discarded בזמן שהדף מושבת. הסיבה לכך היא שבדרך כלל דפים נמחקים כשיש מגבלות על המשאבים, ופשוט אי אפשר לבטל את ההקפאה של דף כדי לאפשר לסקריפט לפעול בתגובה לאירוע מחיקה ברוב המקרים. לכן, כדאי להתכונן לאפשרות שהשינוי ממוסתר לקפוא יימחק. לאחר מכן, אפשר להגיב לשחזור של דף שנמחק בזמן טעינת הדף על ידי בדיקת |
שוב, מכיוון שהאמינות והסדר של אירועי מחזור החיים לא מיושמים באופן עקבי בכל הדפדפנים, הדרך הקלה ביותר לפעול לפי ההמלצות שבטבלה היא להשתמש ב-PageLifecycle.js.
ממשקי API מדור קודם שקשורים למחזור החיים של המשתמשים שכדאי להימנע מהם
מומלץ להימנע מהאירועים הבאים ככל האפשר.
האירוע unload
מפתחים רבים מתייחסים לאירוע unload כאל קריאה חוזרת מובטחת ומשתמשים בו כאות לסיום הסשן כדי לשמור את המצב ולשלוח נתוני ניתוח, אבל השימוש הזה לא אמין במיוחד, במיוחד בנייד! האירוע unload לא מופעל בהרבה מצבים אופייניים של ביטול טעינה, כולל סגירת כרטיסייה מתוך הכרטיסייה 'מעבר בין כרטיסיות' בנייד או סגירת אפליקציית הדפדפן מתוך הכרטיסייה 'מעבר בין אפליקציות'.
לכן, תמיד עדיף להסתמך על האירוע visibilitychange כדי לקבוע מתי סשן מסתיים, ולהתייחס למצב המוסתר כאל הזמן המהימן האחרון לשמירת נתונים של האפליקציה והמשתמש.
בנוסף, עצם הנוכחות של handler רשום של האירוע unload (באמצעות onunload או addEventListener()) יכולה למנוע מהדפדפנים להכניס דפים למטמון לדף הקודם/הבא כדי לטעון מהר יותר את הדפים הקודמים והבאים.
בכל הדפדפנים המודרניים, מומלץ להשתמש תמיד באירוע pagehide כדי לזהות אפשרויות של ביטול טעינה של דף (כלומר, המצב terminated) במקום באירוע unload. אם אתם צריכים לתמוך בגרסאות 10 ומטה של Internet Explorer, אתם צריכים לזהות את התכונה של אירוע 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. event.returnValue = true; } }); במקום זאת, כדאי לעשות את זה (כי הפונקציה beforeunload listener מתווספת רק כשצריך אותה, ומוסרת כשלא צריך אותה):
const beforeUnloadListener = (event) => { event.preventDefault(); // Legacy support for older browsers. event.returnValue = true; }; // A function that adds a `beforeunload` listener if there are unsaved changes. onPageHasUnsavedChanges(() => { addEventListener('beforeunload', beforeUnloadListener); }); // A function that removes the `beforeunload` listener when the page's unsaved // changes are resolved. onAllChangesSaved(() => { removeEventListener('beforeunload', beforeUnloadListener); }); שאלות נפוצות
למה אין מצב 'טעינה'?
ה-API של מחזור החיים של הדף מגדיר מצבים נפרדים שאי אפשר להפעיל אותם בו-זמנית. דף יכול להיטען במצב פעיל, פסיבי או מוסתר, והמצבים האלה יכולים להשתנות – או אפילו להיפסק – לפני שהטעינה מסתיימת. לכן, אין טעם להשתמש במצב טעינה נפרד בפרדיגמה הזו.
הדף שלי מבצע פעולות חשובות כשהוא מוסתר. איך אפשר למנוע את ההקפאה או ההסרה שלו?
יש הרבה סיבות לגיטימיות לכך שדפי אינטרנט לא צריכים להיות במצב קפוא בזמן שהם פועלים במצב מוסתר. הדוגמה הכי ברורה היא אפליקציה שמנגנת מוזיקה.
יש גם מצבים שבהם יהיה מסוכן ל-Chrome להסיר דף, למשל אם הוא מכיל טופס עם קלט משתמש שלא נשלח, או אם יש לו beforeunload handler שמציג אזהרה כשהדף מוסר.
בשלב הזה, Chrome יפעל בצורה שמרנית כשמדובר בהסרת דפים, ויעשה זאת רק אם הוא בטוח שהפעולה לא תשפיע על המשתמשים. לדוגמה, דפים שנצפו מבצעים אחת מהפעולות הבאות בזמן שהם במצב מוסתר לא יימחקו, אלא אם יש מגבלות קיצוניות על המשאבים:
- הפעלת אודיו
- שימוש ב-WebRTC
- עדכון הכותרת של הטבלה או סמל האתר
- הצגת התראות
- שליחת התראות
כדי לראות את רשימת התכונות הנוכחית שמשמשת לקביעה אם אפשר להקפיא או לסגור כרטיסייה בצורה בטוחה, אפשר לעיין במאמר בנושא היוריסטיקה להקפאה ולסגירה ב-Chrome.
מטמון לדף הקודם/הבא הוא מונח שמתאר אופטימיזציה של ניווט שחלק מהדפדפנים מיישמים, כדי להאיץ את השימוש בכפתורים 'הקודם' ו'הבא'.
כשמשתמש עובר מדף מסוים, הדפדפנים האלה מקפיאים גרסה של הדף כדי שאפשר יהיה לחזור אליו במהירות אם המשתמש ינווט חזרה באמצעות הלחצנים 'הקודם' או 'הבא'. חשוב לזכור: הוספה של unloadגורם מטפל באירועים מונעת את האפשרות לבצע את האופטימיזציה הזו.
לכל המטרות, ההקפאה הזו זהה מבחינה פונקציונלית להקפאה של דפדפנים כדי לחסוך במעבד או בסוללה. לכן היא נחשבת לחלק ממצב מחזור החיים מוקפא.
אם אי אפשר להפעיל ממשקי API אסינכרוניים במצבים קפואים או במצבים של סיום, איך אפשר לשמור נתונים ב-IndexedDB?
במצבים של הקפאה וסיום, משימות שניתנות להקפאה בתורי המשימות של דף מושעות, מה שאומר שאי אפשר להשתמש בממשקי API אסינכרוניים ומבוססי קריאה חוזרת באופן מהימן.
רוב ממשקי ה-API של IndexedDB מבוססים על קריאות חוזרות (callback), אבל השיטה commit() בממשק IDBTransaction מספקת דרך להתחיל את תהליך השליחה בעסקה פעילה בלי לחכות לאירועים מבקשות ממתינות. השיטה הזו מספקת דרך אמינה לשמירת נתונים במסד נתונים של IndexedDB במאזין אירועים מסוג freeze או visibilitychange, כי הפעולה commit מופעלת באופן מיידי ולא מתווספת לתור במשימה נפרדת.
בדיקת האפליקציה במצבים 'מוקפא' ו'הוצאה מהזיכרון'
כדי לבדוק איך האפליקציה מתנהגת במצבים של הקפאה וסגירה, אפשר להיכנס לכתובת chrome://discards כדי להקפיא או לסגור בפועל כל אחד מהכרטיסיות הפתוחות.
כך תוכלו לוודא שהדף מטפל בצורה נכונה באירועים freeze ו-resume וגם בדגל document.wasDiscarded כשדפים נטענים מחדש אחרי שהם נמחקו.
סיכום
מפתחים שרוצים להתחשב במשאבי המערכת של המכשירים של המשתמשים שלהם צריכים לפתח את האפליקציות שלהם תוך התחשבות במצבי מחזור החיים של הדף. חשוב מאוד שדפי אינטרנט לא יצרכו משאבי מערכת מוגזמים במצבים שהמשתמש לא מצפה להם
ככל שיותר מפתחים יתחילו להטמיע את ממשקי ה-API החדשים של מחזור החיים של הדף, כך יהיה בטוח יותר לדפדפנים להקפיא ולבטל דפים שלא נמצאים בשימוש. המשמעות היא שדפדפנים יצרכו פחות זיכרון, מעבד, סוללה ומשאבי רשת, וזה יתרון למשתמשים.