Page Lifecycle API

Android、iOS 和最新的 Windows 系統能夠隨時自主地中止後臺進程,及時釋放系統資源。也就是說,網頁可能隨時被系統丟棄掉。之前的瀏覽器 API 徹底沒有考慮到這種狀況,致使開發者根本沒有辦法監聽到系統丟棄頁面。javascript

爲了解決這個問題,W3C 新制定了一個 Page Lifecycle API,統一了網頁從誕生到卸載的行爲模式,而且定義了新的事件,容許開發者響應網頁狀態的各類轉換。java

有了這個 API,開發者就能夠預測網頁下一步的狀態,從而進行各類針對性的處理。Chrome 68 支持這個 API,對於老式瀏覽器可使用谷歌開發的兼容庫 PageLifecycle.js。瀏覽器

生命週期階段

網頁的生命週期分紅六個階段,每一個時刻只可能處於其中一個階段。緩存

(1)Active 階段服務器

在 Active 階段,網頁處於可見狀態,且擁有輸入焦點。網絡

(2)Passive 階段ide

在 Passive 階段,網頁可見,但沒有輸入焦點,沒法接受輸入。UI 更新(好比動畫)仍然在執行。該階段只可能發生在桌面同時有多個窗口的狀況。函數

(3)Hidden 階段動畫

在 Hidden 階段,用戶的桌面被其餘窗口占據,網頁不可見,但還沒有凍結。UI 更新再也不執行。code

(4)Terminated 階段

在 Terminated 階段,因爲用戶主動關閉窗口,或者在同一個窗口前往其餘頁面,致使當前頁面開始被瀏覽器卸載並從內存中清除。注意,這個階段老是在 Hidden 階段以後發生,也就是說,用戶主動離開當前頁面,老是先進入 Hidden 階段,再進入 Terminated 階段。

這個階段會致使網頁卸載,任何新任務都不會在這個階段啓動,而且若是運行時間太長,正在進行的任務可能會被終止。

(5)Frozen 階段

若是網頁處於 Hidden 階段的時間太久,用戶又不關閉網頁,瀏覽器就有可能凍結網頁,使其進入 Frozen 階段。不過,也有可能,處於可見狀態的頁面長時間沒有操做,也會進入 Frozen 階段。

這個階段的特徵是,網頁不會再被分配 CPU 計算資源。定時器、回調函數、網絡請求、DOM 操做都不會執行,不過正在運行的任務會執行完。瀏覽器可能會容許 Frozen 階段的頁面,週期性復甦一小段時間,短暫變回 Hidden 狀態,容許一小部分任務執行。

(6)Discarded 階段

若是網頁長時間處於 Frozen 階段,用戶又不喚醒頁面,那麼就會進入 Discarded 階段,即瀏覽器自動卸載網頁,清除該網頁的內存佔用。不過,Passive 階段的網頁若是長時間沒有互動,也可能直接進入 Discarded 階段。

這通常是在用戶沒有介入的狀況下,由系統強制執行。任何類型的新任務或 JavaScript 代碼,都不能在此階段執行,由於這時一般處在資源限制的情況下。

網頁被瀏覽器自動 Discarded 之後,它的 Tab 窗口仍是在的。若是用戶從新訪問這個 Tab 頁,瀏覽器將會從新向服務器發出請求,再一次從新加載網頁,回到 Active 階段。

常見場景

如下是幾個常見場景的網頁生命週期變化。

(1)用戶打開網頁後,又切換到其餘 App,但只過了一會又回到網頁。

網頁由 Active 變成 Hidden,又變回 Active。

(2)用戶打開網頁後,又切換到其餘 App,而且長時候使用後者,致使系統自動丟棄網頁。

網頁由 Active 變成 Hidden,再變成 Frozen,最後 Discarded。

(3)用戶打開網頁後,又切換到其餘 App,而後從任務管理器裏面將瀏覽器進程清除。

網頁由 Active 變成 Hidden,而後 Terminated。

(4)系統丟棄了某個 Tab 裏面的頁面後,用戶從新打開這個 Tab。

網頁由 Discarded 變成 Active。

事件

生命週期的各個階段都有本身的事件,以供開發者指定監聽函數。這些事件裏面,只有兩個是新定義的(freeze事件和resume事件),其它都是現有的。

注意,網頁的生命週期事件是在全部幀(frame)觸發,不論是底層的幀,仍是內嵌的幀。也就是說,內嵌的<iframe>網頁跟頂層網頁同樣,都會同時監聽到下面的事件。

focus 事件

focus事件在頁面得到輸入焦點時觸發,好比網頁從 Passive 階段變爲 Active 階段。

blur 事件

blur事件在頁面失去輸入焦點時觸發,好比網頁從 Active 階段變爲 Passive 階段。

visibilitychange 事件

visibilitychange事件在網頁可見狀態發生變化時觸發,通常發生在如下幾種場景。

  • 用戶隱藏頁面(切換 Tab、最小化瀏覽器),頁面由 Active 階段變成 Hidden 階段。
  • 用戶從新訪問隱藏的頁面,頁面由 Hidden 階段變成 Active 階段。
  • 用戶關閉頁面,頁面會先進入 Hidden 階段,而後進入 Terminated 階段。
    能夠經過document.onvisibilitychange屬性指定這個事件的回調函數。

freeze 事件

freeze事件在網頁進入 Frozen 階段時觸發。

能夠經過document.onfreeze屬性指定在進入 Frozen 階段時調用的回調函數。

function handleFreeze(e) {
  // Handle transition to FROZEN
}
document.addEventListener('freeze', handleFreeze);
# 或者
document.onfreeze = function() { … }

這個事件的監聽函數,最長只能運行500毫秒。而且只能複用已經打開的網絡鏈接,不能發起新的網絡請求。

注意,從 Frozen 階段進入 Discarded 階段,不會觸發任何事件,沒法指定回調函數,只能在進入 Frozen 階段時指定回調函數。

resume 事件

resume事件在網頁離開 Frozen 階段,變爲 Active / Passive / Hidden 階段時觸發。

document.onresume屬性指的是頁面離開 Frozen 階段、進入可用狀態時調用的回調函數。

function handleResume(e) {
  // handle state transition FROZEN -> ACTIVE
}
document.addEventListener("resume", handleResume);
# 或者
document.onresume = function() { … }

pageshow 事件

pageshow事件在用戶加載網頁時觸發。這時,有多是全新的頁面加載,也多是從緩存中獲取的頁面。若是是從緩存中獲取,則該事件對象的event.persisted屬性爲true,不然爲false

這個事件的名字有點誤導,它跟頁面的可見性其實毫無關係,只跟瀏覽器的 History 記錄的變化有關。

pagehide 事件

pagehide事件在用戶離開當前網頁、進入另外一個網頁時觸發。它的前提是瀏覽器的 History 記錄必須發生變化,跟網頁是否可見無關。

若是瀏覽器可以將當前頁面添加到緩存以供稍後重用,則事件對象的event.persisted屬性爲true。 若是爲true。若是頁面添加到了緩存,則頁面進入 Frozen 狀態,不然進入 Terminatied 狀態。

beforeunload 事件

beforeunload事件在窗口或文檔即將卸載時觸發。該事件發生時,文檔仍然可見,此時卸載仍可取消。通過這個事件,網頁進入 Terminated 狀態。

unload 事件

unload事件在頁面正在卸載時觸發。通過這個事件,網頁進入 Terminated 狀態。

獲取當前階段

若是網頁處於 Active、Passive 或 Hidden 階段,能夠經過下面的代碼,得到網頁當前的狀態。

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

若是網頁處於 Frozen 和 Terminated 狀態,因爲定時器代碼不會執行,只能經過事件監聽判斷狀態。進入 Frozen 階段,能夠監聽freeze事件;進入 Terminated 階段,能夠監聽pagehide事件。

document.wasDiscarded

若是某個選項卡處於 Frozen 階段,就隨時有可能被系統丟棄,進入 Discarded 階段。若是後來用戶再次點擊該選項卡,瀏覽器會從新加載該頁面。

這時,開發者能夠經過判斷document.wasDiscarded屬性,瞭解先前的網頁是否被丟棄了。

if (document.wasDiscarded) {
  // 該網頁已經不是原來的狀態了,曾經被瀏覽器丟棄過
  // 恢復之前的狀態
  getPersistedState(self.discardedClientId);
}

同時,window對象上會新增window.clientIdwindow.discardedClientId兩個屬性,用來恢復丟棄前的狀態。

相關文章
相關標籤/搜索