其他常見事件

資源事件

1 .beforeunload

1 .在窗口,文檔,各種資源將要卸載前觸發(fā),可以用來防止用戶不小心卸載資源,比如一個(gè)表格填了很多但是一不小心點(diǎn)擊了關(guān)閉。
2 .經(jīng)過測(cè)試發(fā)現(xiàn),只有界面中有表單,而且表單已經(jīng)填寫的時(shí)候才會(huì)觸發(fā)事件。只有這一種情況需要使用此事件
3 .此事件執(zhí)行優(yōu)于unload,也就是說可以阻止掉onload事件的執(zhí)行
4 .新窗口打開不會(huì)執(zhí)行,只在刷新和關(guān)閉時(shí)執(zhí)行
5 .只能用于警告用戶有未保存的改變。一但保存之后,事件應(yīng)該會(huì)被清除,這樣對(duì)頁面的性能有影響

2 .unload

1 .窗口新打開,刷新,關(guān)閉的時(shí)候都會(huì)執(zhí)行

3 .指定以上兩個(gè)事件的監(jiān)聽函數(shù),瀏覽器就不會(huì)緩存當(dāng)前頁面。所以任何時(shí)候都不要指定這些事件

html頁面的生命周期

1 .DOMContentLoaded:瀏覽器已經(jīng)完全加載了html,dom樹已經(jīng)構(gòu)建完畢,但是像img和樣式表等外部資源并沒有下載完畢

1 .DOM加載完畢,js可以訪問所有dom節(jié)點(diǎn),初始化界面
2 .由document觸發(fā),所以要在這個(gè)上面監(jiān)聽
3 .瀏覽器的自動(dòng)補(bǔ)全:如果有登錄界面,瀏覽器記住了該頁面的用戶名和密碼,那么在DOMContentLoaded運(yùn)行的時(shí)候?yàn)g覽器會(huì)自動(dòng)補(bǔ)全表單
4 .async和defer腳本可能還沒有執(zhí)行

2 .load:附件資源已經(jīng)加載完畢,在此時(shí)事件觸發(fā)可以獲得圖像的大小,如果沒有在html,css中指定

1 .會(huì)在所有文件包括樣式表,圖片和其他資源下載完畢之后觸發(fā)
2 .一般不會(huì)用到這個(gè)事件,不需要等那么久

3 .beforeunload/unload:用戶正在離開頁面,可以詢問用戶是否保存了更改以及確定是否要離開頁面

檢測(cè)頁面的狀態(tài)

1 .document.readyState:

1 .loading:加載,document任然在加載
2 .interactive:互動(dòng)。文檔已經(jīng)完成加載,文檔已經(jīng)被解析,但是諸如圖像,樣式表和框架之類的子資源任然在加載
3 .complete:文檔和所有子資源已完成加載,狀態(tài)表示load事件即將被觸發(fā)

退出當(dāng)前頁面

1 .一個(gè)非常消耗后臺(tái)運(yùn)算的請(qǐng)求,在用戶退出當(dāng)前頁面的時(shí)候,要求前端發(fā)送一個(gè)請(qǐng)求來殺死任務(wù)
2 .場(chǎng)景:

1 .還在本網(wǎng)站,跳到其他路由。從本頁面前往別的頁面 
2 .刷新,關(guān)閉頁面的時(shí)候。unload事件+beacon api 注意,在頁面關(guān)閉的時(shí)候是無法異步發(fā)送信息的,所以使用這個(gè)方法

3 .

Page Lifecycle API

1 .為了彌補(bǔ)page visibility api只能在網(wǎng)頁對(duì)用戶不可見時(shí)觸發(fā),無法知道網(wǎng)頁被系統(tǒng)隨時(shí)丟掉的情況。制定了新的規(guī)則,定義了這個(gè)事件,允許開發(fā)者響應(yīng)網(wǎng)頁狀態(tài)的各種轉(zhuǎn)換
2 .統(tǒng)一了網(wǎng)頁從誕生到卸載的行為模式,并定義了新的事件,允許開發(fā)者響應(yīng)網(wǎng)頁狀態(tài)的各種轉(zhuǎn)換
3 .6種狀態(tài)

1 .active:網(wǎng)頁處于可見狀態(tài),且擁有輸入焦點(diǎn)
2 .passive階段:網(wǎng)頁可見,但是沒有輸入檢點(diǎn),無法接受輸入。ui更新任然在執(zhí)行,該階段只能發(fā)生在桌面同時(shí)有多個(gè)窗口的時(shí)候。
3 .hidden:用戶的桌面被其他窗口占據(jù),網(wǎng)頁不可見,但是尚未凍結(jié),ui更新不在執(zhí)行(比如一些ui動(dòng)畫)
4 .terminated:用戶主動(dòng)關(guān)閉窗口,或者在同一個(gè)窗口前往其他頁面,導(dǎo)致當(dāng)前頁面開始被瀏覽器卸載并從內(nèi)存中清除。注意這個(gè)階段總是在hidden之后發(fā)生,也就是說,當(dāng)用戶主動(dòng)離開當(dāng)前頁面,總是先進(jìn)入hidden階段,然后在進(jìn)入terminated階段。這個(gè)階段會(huì)導(dǎo)致網(wǎng)頁卸載,任何新的任務(wù)都不會(huì)再這個(gè)階段啟動(dòng),并且如果運(yùn)行時(shí)間太長,正在進(jìn)行的任務(wù)可能也會(huì)被終止
5 .Forzen:如果網(wǎng)頁處于hidden階段太久,用戶又不關(guān)閉網(wǎng)頁,瀏覽器就有可能凍結(jié)網(wǎng)頁,當(dāng)用戶處于可見狀態(tài)長時(shí)間沒有操作,也會(huì)進(jìn)入forzen狀態(tài)。當(dāng)處于這個(gè)階段的時(shí)候,網(wǎng)頁不會(huì)再分配CPU計(jì)算資源。定時(shí)器,回調(diào)函數(shù),網(wǎng)絡(luò)請(qǐng)求,dom操作都不會(huì)執(zhí)行,不過正在運(yùn)行的任務(wù)會(huì)執(zhí)行完畢。瀏覽器可能會(huì)允許forzen階段的頁面,周期性的復(fù)蘇一小段時(shí)間,短暫的變回hidden階段,允許一小部分任務(wù)執(zhí)行
6 .discarded:處于forzen階段,用戶又不喚醒頁面,就會(huì)進(jìn)入discarded階段,瀏覽器自動(dòng)卸載網(wǎng)頁,清除該網(wǎng)頁的內(nèi)存占用。這一般是在用戶沒有介入的情況下,系統(tǒng)強(qiáng)制執(zhí)行,任何類型的新任務(wù)或者js代碼,都不會(huì)再此階段執(zhí)行,因?yàn)檫@個(gè)時(shí)候通常處在資源限制的情況下.網(wǎng)頁被瀏覽器自動(dòng)discarded以后。tab窗口還是存在,如果用戶重新訪問這個(gè)tab頁面,瀏覽器將會(huì)重新向服務(wù)器發(fā)出請(qǐng)求,再一次重新加載網(wǎng)頁,回到active階段

4 .常見場(chǎng)景的切換

1 .打開網(wǎng)頁->切換到其他app->回到網(wǎng)頁(active-hidden-active)
2 .打開網(wǎng)頁->切換到其他app->長時(shí)間使用后者,系統(tǒng)自動(dòng)丟棄網(wǎng)頁(active-hidden-frozen-discarded)
3 .打開網(wǎng)頁->切換到其他app->從任務(wù)管理器將瀏覽器進(jìn)程清除(active-hidden-terminated)
4 .系統(tǒng)丟棄了某個(gè)tab里面的頁面后,用戶重新打開這個(gè)tab(discarded-active)
5 .頁面獲得焦點(diǎn)時(shí)focus(passive-active)
6 .頁面失去焦點(diǎn)的時(shí)候(active-passive)
7 .用戶隱藏頁面(切換tab,最小化瀏覽器),頁面由active階段變成hidden階段
8 .用戶重新訪問隱藏的頁面(hidden-active)
9 .freeze:網(wǎng)頁進(jìn)入frozen階段觸發(fā) document.addEventListener('forzen',fn) 注意:這個(gè)事件的監(jiān)聽函數(shù),最長只能運(yùn)行500mm,并且只能復(fù)用已經(jīng)打開的網(wǎng)絡(luò)鏈接,不能發(fā)起新的網(wǎng)絡(luò)請(qǐng)求
10 .從Frozen階段進(jìn)入discarded階段,不會(huì)觸發(fā)任何事件,無法指定回調(diào)函數(shù),只能在進(jìn)入forzen階段時(shí)指定回調(diào)函數(shù)
11 .resume:網(wǎng)頁離開forzen階段,變?yōu)閍ctive.passive,hidden階段觸發(fā)
12 .pageshow:用戶加載網(wǎng)頁時(shí)觸發(fā)。全新的網(wǎng)頁加載:e.persisted屬性為true,否則為false。會(huì)話歷史新增一條記錄
13 .pagehide:用戶離開當(dāng)前網(wǎng)絡(luò),進(jìn)入另一個(gè)網(wǎng)頁時(shí)觸發(fā),這個(gè)事件和網(wǎng)頁的可見性沒有任何關(guān)系,主要是看瀏覽器的history記錄變化有關(guān)
14 .http://www.imooc.com/article/74160

事件

1 .網(wǎng)頁的生命周期事件在所有的frame觸發(fā),不管是底層的,還會(huì)內(nèi)嵌的,都會(huì)監(jiān)聽到下面的事件
2 .獲取當(dāng)前網(wǎng)頁狀態(tài)

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};
1 .Forzen狀態(tài):監(jiān)聽freeze事件
2 .terminated:監(jiān)聽pagehide事件
3 .document.wasDiscarded:了解當(dāng)前網(wǎng)頁是否被丟棄過

3 .所有頁面的生命周期都是相互獨(dú)立存在的,也就是說一個(gè)頁面在同一時(shí)間點(diǎn)只能存在一個(gè)狀態(tài),而且通常大多數(shù)頁面聲明周期的狀態(tài)修改都是通過dom事件監(jiān)聽
4 .瀏覽器會(huì)發(fā)送許多事件,但是只有小部分世界表明頁面周期狀態(tài)可能發(fā)生變化
5 .unload,beforeunload也會(huì)觸發(fā)事件,但是盡量不要用

Page Visibility API

1 .開發(fā)者需要知道,用戶正在離開頁面,一般是監(jiān)聽以下事件

1 .pagehide
2 .beforeunload
3 .unload

2 .局限性:在手機(jī)上面不會(huì)觸發(fā),頁面會(huì)直接關(guān)閉。比如以下幾種場(chǎng)景

1 .用戶點(diǎn)了一條系統(tǒng)通知,切換到了另一個(gè)app
2 .用戶進(jìn)入任務(wù)切換窗口,切換到下一個(gè)app
3 .用戶點(diǎn)擊home鍵

3 .監(jiān)聽網(wǎng)頁的狀態(tài),一旦用戶不看網(wǎng)頁,很多網(wǎng)頁行為都可以暫停

1 .對(duì)服務(wù)器的輪詢
2 .網(wǎng)頁動(dòng)畫
3 .正在播放的視頻或音頻

document.visibilityState

1 .表示當(dāng)前頁面狀態(tài)的值

1 .hidden:頁面徹底不可見
2 .visible:頁面至少一部分可見
3 .prerender:頁面即將或者正在渲染,處于不可見狀態(tài)

2 .返回hidden的時(shí)候

1 .瀏覽器最小化
2 .當(dāng)前頁面切換成了背景頁
3 .瀏覽器將要卸載頁面
4 .操作系統(tǒng)觸發(fā)鎖屏屏幕
5 .

3 .這個(gè)屬性只針對(duì)頂層窗口,內(nèi)嵌的iframe頁面的這個(gè)屬性由頂層窗口決定。使用css屬性影藏iframe頁面是不會(huì)影響內(nèi)嵌頁面的可見性的
4 .

visibilitychange事件

document.addEventListener('visibilitychange',(e)=>{
            console.log(e)
            if(document.visibilityState==='hidden'){
                document.title='頁面不可見'
            }
            if(document.visibilityState==='visible'){
                document.title='可見'
            }
        })

如何正確監(jiān)聽頁面卸載

1 .只需要監(jiān)聽上面說的那個(gè)事件即可,別的都不可靠

觀察頁面內(nèi)的生命狀態(tài)

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;
  }
};

// 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()), {capture: true});
});

// 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');
}, {capture: true});

window.addEventListener('pagehide', (event) => {
  if (event.persisted) {
    // If the event's persisted property is true the page is about
    // to enter the page navigation cache, which is also in the frozen state.    logStateChange('frozen');
  } else {
    // If the event's persisted property is not true the page is
    // about to be unloaded.    logStateChange('terminated');
  }
}, {capture: true});

1 .傳入capture:true的原因

1 .不是所有的生命周期事件的target都是一致,pagehide和pageshow事件在window山觸發(fā),visibilitychange,freeze以及resume事件在document上觸發(fā),而focus和blur事件會(huì)在他們各自的dom上觸發(fā)
2 .這些事件不部分是不會(huì)冒泡的,這就意味著不能再公共的祖先上添加非捕獲事件監(jiān)聽器監(jiān)聽所有事件
3 .捕獲階段在目標(biāo)冒泡階段之前執(zhí)行,所以在此添加事件監(jiān)聽器能保證他能在其他代碼取消他們之前執(zhí)行

2 .瀏覽器兼容問題

1 .當(dāng)切換標(biāo)簽頁時(shí)有些瀏覽器沒有觸發(fā)blur事件。這就意味著頁面可以直接從active狀態(tài)進(jìn)入hidden狀態(tài)而不會(huì)先轉(zhuǎn)為passive狀態(tài)
2 .個(gè)別瀏覽器實(shí)現(xiàn)了頁面導(dǎo)航緩存,而頁面生命周期api定義了緩存的頁面處于凍結(jié)狀態(tài)。由于api完全是新的,所以這些瀏覽器還未實(shí)現(xiàn)freeze和resume事件,盡管這些狀態(tài)仍然可以通過pagehide,pageshow事件被監(jiān)聽到
3 .ie瀏覽器沒有實(shí)現(xiàn)visibility事件
4 .pagehide和visibilitychange事件的發(fā)生順序有所改變。如果在寫在頁面時(shí),并且頁面處于可見狀態(tài),早起瀏覽器會(huì)先觸發(fā)pagehide事件然后在觸發(fā)visibilitychange事件。新的chrome事件則是先觸發(fā)visibility事件然后再出發(fā)pagehide事件,無論卸載時(shí)文檔是否為可見狀態(tài)
5 .pagelifecycle.js規(guī)范了跨瀏覽器的事件觸發(fā)順序差異,就可以準(zhǔn)確的按照約定觸發(fā)事件了。

3 .對(duì)各種狀態(tài)的理解

1 .active:對(duì)用戶來說,active狀態(tài)是最關(guān)鍵的,這個(gè)時(shí)候最關(guān)鍵的是響應(yīng)用戶的輸入,因此任何可能阻止主線程的非ui工作都應(yīng)該被停止或者使用web worker來執(zhí)行

2 .在passive狀態(tài)時(shí),用戶不會(huì)與頁面互動(dòng),但是仍對(duì)用戶可見。這也就是說ui更新及動(dòng)畫依然會(huì)很流暢,但是更新事件就沒那么重要了。當(dāng)頁面從active改為passive時(shí),現(xiàn)在是保持未保存的應(yīng)用程序狀態(tài)的最好時(shí)機(jī)

3 .hidden:開發(fā)者能最可靠的監(jiān)聽到的最后的狀態(tài)變化就是頁面轉(zhuǎn)化為hidden狀態(tài)。特別是在移動(dòng)設(shè)備上,因?yàn)橛脩艨梢躁P(guān)掉tab或者瀏覽器,此時(shí),beforeunload,pagehide,unload事件都不會(huì)觸發(fā)。在這個(gè)時(shí)候。該保存所有沒有保存的應(yīng)用狀態(tài)發(fā)送還未發(fā)送的所有需要分析的數(shù)據(jù)。這個(gè)時(shí)候也應(yīng)該停止更新ui了,也要關(guān)閉所有用戶不希望在后臺(tái)運(yùn)行的程序

4 .forzen:頁面從hidden轉(zhuǎn)為forzen狀態(tài)時(shí),必須停止任何計(jì)時(shí)器或拆除任何連接,如果凍結(jié),可能會(huì)影響同一源的其他open選項(xiàng)卡標(biāo)簽,或影響瀏覽器將頁面放入頁面導(dǎo)航緩存的能力
4.1 .將任何動(dòng)態(tài)的視圖狀態(tài)(無限滾動(dòng)列表視圖的滾動(dòng)位置)保存到sessionStorage,這樣隨后頁面被拋棄又被重新加載就能恢復(fù)到原來的狀態(tài)
4.2 .關(guān)閉所有打開的indexDB連接,關(guān)閉打開的BroadcastChange連接,關(guān)閉打開的webRTC連接,停止所有網(wǎng)絡(luò)輪詢以及所有打開的web Socket連接,釋放所有被保存的web Locks.當(dāng)頁面從forzen轉(zhuǎn)變?yōu)閔idden的時(shí)候,可以重新打開在任何凍結(jié)時(shí)刻關(guān)閉的連接或重啟那時(shí)被停止的輪詢

5 .terminated:值得注意的是,依靠termination事件,beforeunload,pagehide,unload事件是不可靠的,特別是在移動(dòng)端的時(shí)候

6 .discarded:當(dāng)頁面正被拋棄的時(shí)候,這個(gè)狀態(tài)是不可能被監(jiān)聽到的,所以要做好在hidden轉(zhuǎn)為forzen的時(shí)候頁面被拋棄的準(zhǔn)備

避免舊版本的生命周期api

1 .unload事件

1 .現(xiàn)代瀏覽器中千萬不要使用unload事件
2 .在很多情況,unload事件并不會(huì)觸發(fā),不能保證回調(diào),所以是不能作為結(jié)束會(huì)話的信號(hào)來保存狀態(tài)或者發(fā)送數(shù)據(jù)。
3 .特別是移動(dòng)設(shè)備上,unload事件在一些典型的unload場(chǎng)景中并沒有觸發(fā),包括從移動(dòng)設(shè)備上標(biāo)簽切換器上關(guān)閉標(biāo)簽或者直接關(guān)閉瀏覽器app
4 .現(xiàn)代瀏覽器總是推薦使用pagehide事件來檢測(cè)頁面是否被卸載而不是使用unload事件

2 .beforeunload事件

1 .不要無條件的添加beforeunload監(jiān)聽器或?qū)⑵渥鳛闀?huì)話結(jié)束的信號(hào)
2 .僅在用戶未保存的工作時(shí)添加,并在保存工作以后立即將其刪除
3 .當(dāng)這個(gè)事件阿生時(shí)會(huì)阻止瀏覽器在頁面導(dǎo)航緩存中緩存頁面
4 .pageliftcycle.js中提供了addUnsavedChanges和removeUnsaveChanges事件來對(duì)這種情況做了最佳的實(shí)踐,所以可以使用這個(gè)事件
5 .

常見問題

1 .如何避免頁面在hidden的時(shí)候不被凍結(jié)或者拋棄

1 .比如當(dāng)app在播放音樂的時(shí)候
2 .chrome丟棄頁面的時(shí)候很保守,只有有把握不會(huì)影響用戶時(shí)才會(huì)這樣做,例如會(huì)檢查以下情況,播放音頻,使用webRtc,更新表格標(biāo)題或圖標(biāo),彈出警告時(shí),發(fā)出推送通知
3 .

2 .頁面緩存導(dǎo)航

1 .是一種幫助瀏覽器實(shí)現(xiàn)更快前進(jìn)或者后退按鈕的導(dǎo)航優(yōu)化
2 .當(dāng)用戶離開網(wǎng)頁的時(shí)候,這些瀏覽器會(huì)凍結(jié)該頁面的版本,以便用戶使用前進(jìn)或后退按鈕導(dǎo)航時(shí)能快速恢復(fù)。

3 .在frozen或terminated狀態(tài)不能執(zhí)行異步api,如何保存數(shù)據(jù)到indexedDB

1 .在forzen或terminated狀態(tài)下,在頁面任務(wù)隊(duì)列里的凍結(jié)任務(wù)會(huì)被掛起,也就是說不能可靠的調(diào)用異步操作或基于api的回調(diào)
2 .未來indexDB會(huì)有一個(gè)commit事件,會(huì)保證完成寫入數(shù)據(jù)的操作
3 .現(xiàn)在有兩種選擇,使用localStprage或者service worker中使用indexDB,在頁面被終止或者丟棄時(shí),使用postmessage發(fā)送數(shù)據(jù)到serveice worker
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??JavaScript 與 HTML 之間的交互是通過事件實(shí)現(xiàn)的。 ??事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,678評(píng)論 1 11
  • 頁面生命周期:DOMContentLoaded, load, beforeunload, unload HTML頁...
    Amfishers閱讀 9,732評(píng)論 0 5
  • HTML頁面的生命周期有以下三個(gè)重要事件:1)DOMContentLoaded:瀏覽器已經(jīng)完全加載了HTML,DO...
    puxiaotaoc閱讀 971評(píng)論 0 1
  • 本節(jié)介紹各種常見的瀏覽器事件。 鼠標(biāo)事件 鼠標(biāo)事件指與鼠標(biāo)相關(guān)的事件,主要有以下一些。 click 事件,dblc...
    許先生__閱讀 2,827評(píng)論 0 4
  • JavaScript 與 HTML 之間的交互是通過事件實(shí)現(xiàn)的。事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬...
    LemonnYan閱讀 736評(píng)論 0 4

友情鏈接更多精彩內(nèi)容