譯者:@飄飄
作者:@Viduni Wickramarachchi
原文:https://blog.bitsrc.io/page-lifecycle-api-a-browser-api-every-frontend-developer-should-know-b1c74948bd74
前言
曾經碰到過這麼個場景,統計用戶在該遊戲停留時間。文章由@飄飄翻譯。
每個前端開發人員都應該知道的瀏覽器API
作爲用戶,我們在瀏覽網頁時總喜歡一心多用。因此,打開多個瀏覽器標籤頁是很常見的,因爲這有助於並行完成事情。但同時,每一個標籤頁都會消耗系統資源,比如內存和CPU。
由於不可能限制用戶打開新的瀏覽器標籤頁並將其留下,因此瀏覽器採取了一些措施,以在瀏覽器標籤頁不活動時重新分配資源。
現在的現代瀏覽器有時會在系統資源緊張的情況下暫停頁面或完全丟棄頁面--菲利普-沃爾頓。
那麼你可能會有疑問,既然瀏覽器已經處理好了,我們爲什麼還要擔心這個問題呢?
並非完全如此,瀏覽器會照顧到一切。此外,這些瀏覽器的干預會直接影響到JavaScript的執行。好消息是,幾乎所有的現代瀏覽器都通過頁面生命週期API將這些干預作爲事件暴露出來。
頁面生命週期API
顧名思義,頁面生命週期API將網頁生命週期的鉤子暴露給JavaScript。然而,這並不是一個全新的概念。頁面可見性API存在了有一段時間,向JavaScript揭示了一些頁面可見性事件。
然而,如果你碰巧在這兩者之間做出選擇,值得一提的是Page Visibility API的一些限制。
它只提供網頁的可見和隱藏狀態。
它不能捕獲被操作系統丟棄的頁面(Android、IOS和最新的Windows系統可以終止後臺進程以保存系統資源)。
我們來看看頁面生命週期API所暴露的頁面生命週期狀態。
頁面生命週期API狀態
在API中介紹了6種狀態,其中有兩種狀態與我們頗爲相關。其中,有兩個狀態與我們相當相關。
FROZEN--CPU暫停的生命週期狀態(隱藏的網頁會被凍結以節約資源)。
如果一個網頁被隱藏了很久,而用戶沒有關閉網頁,瀏覽器會將其凍結,並將網頁移動到這個狀態。但是,正在運行的任務會繼續進行,直到完成。但定時器、回調函數執行和DOM操作將被停止以釋放CPU。
當我查看電腦上Chrome瀏覽器的資源消耗時,我觀察到兩個活動標籤頁分別消耗了14.7%和11%的CPU,而凍結的標籤頁消耗了近0%的CPU。
DISCARDED - 爲了節省資源,將凍結狀態移動到Discarded狀態。
假設一個網頁長時間處於凍結狀態,在這種情況下,瀏覽器會自動將網頁卸載到丟棄狀態,以節省資源。在這種情況下,瀏覽器會自動將頁面卸載到丟棄狀態,釋放一些內存。而如果用戶再次訪問被丟棄的頁面,瀏覽器會重新加載頁面,回到活動狀態。
值得注意的是,用戶一般會在資源受限的設備中體驗到丟棄狀態。
除了以上兩種狀態外,API中還引入了其他四種狀態,分別是:。
ACTIVE - 頁面可見並有輸入焦點。
PASSIVE - 頁面可見,但沒有輸入焦點。
HIDDEN - 頁面不可見(也沒有凍結)。
TERMINATED - 頁面被卸載並從內存中清除。
你可以通過看下圖找到生命週期狀態和過渡的細節。
如何應對生命週期狀態?
現在我們已經瞭解了頁面生命週期API,讓我們看看如何響應每個事件。
這裏最重要的是確定當應用程序達到每個狀態時,哪些需要保留,哪些需要停止。
ACTIVE狀態--由於用戶在頁面上是完全活躍的,所以你的網頁應該完全響應用戶的輸入。任何UI阻塞任務都應該被去掉優先級,比如同步和阻塞網絡請求。
PASSIVE狀態--即使用戶在這個階段沒有與頁面進行交互,他們仍然可以看到它。因此你的網頁應該流暢地運行所有的UI更新和動畫。
HIDDEN狀態 - 隱藏狀態應該被視爲用戶在網頁上的會話的結束。你可以在此時堅持未保存的應用狀態,並停止任何用戶不需要在後臺運行的UI更新或任務。
Frozen狀態 - 任何可能影響其他標籤頁的定時器和連接都應該在這個階段終止。例如,你應該關閉所有打開的IndexedDB連接,任何打開的Web Socket連接,釋放任何被持有的Web鎖,等等。
Terminated狀態 - 由於會話結束邏輯是在隱藏狀態下處理的,所以一般不需要任何操作。
Discarded狀態 - 這個狀態是應用程序無法觀察到的。因此,任何可能的丟棄的準備工作都應該在隱藏或凍結狀態下進行。然而,你可以在頁面加載時通過檢查document.wasDiscarded來對頁面的任何恢復做出反應。
好了,現在我們知道在每個狀態下要做什麼了,讓我們看看如何在我們的應用程序中捕獲每個狀態。
如何在代碼中捕獲生命週期狀態?
你可以使用下面的JavaScript函數來確定一個給定頁面的主動、被動和隱藏狀態。
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
隨着Chrome 68的發佈,開發者可以通過監聽文檔對象上的凍結和恢復事件來觀察隱藏標籤何時被凍結和解凍。
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
要確定一個頁面在隱藏標籤頁中是否被丟棄,可以使用以下代碼。
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
上面提到的wasDiscarded屬性可以在頁面加載時觀察。
瀏覽器兼容性
一些舊的瀏覽器不具備檢測其網頁何時被凍結或丟棄的能力。不過,隨着Chrome 68的發佈,也加入了預測網頁下一步狀態的能力。
已知的兼容性問題
一些瀏覽器在切換標籤頁時沒有觸發模糊事件,這樣可以避免頁面進入被動狀態。
老版本的IE(10及以下)沒有實現visibilityChange事件。
Safari在關閉標籤頁時沒有可靠地觸發pagehide或visibilitychange事件。
爲了克服跨瀏覽器的不兼容性,Google開發了一個名爲Pagelifecycle.js的庫,作爲以下瀏覽器的多維填充。
總結
當用戶沒有積極參與時,網頁不應該消耗過多的資源。此外,你的應用程序還應該知道系統執行的管理任務。Page Lifecycle API介紹了一種簡單的方法來讓你的應用程序知道這些事件。
雖然它更多地與高級用例相關,但我們可以通過了解它的功能來開發高效的網絡應用。因此,我們可以爲終端用戶提供更好的體驗。
1. JavaScript 重溫系列(22篇全)
2. ECMAScript 重溫系列(10篇全)
3. JavaScript設計模式 重溫系列(9篇全)
4.
正則 / 框架 / 算法等 重溫系列(16篇全)
5.
Webpack4 入門(上)
||
Webpack4 入門(下)
6.
MobX 入門(上)
||
MobX 入門(下)
7. 100
+篇原創系列彙總
回覆“加羣”與大佬們一起交流學習~
點擊“閱讀原文”查看 100+ 篇原創文章
本文分享自微信公衆號 - 前端自習課(FE-study)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。