在web項目開發中,關於瀏覽器關閉事件有兩個很常見的問題:爲何我沒有監聽瀏覽器關閉事件? 我監聽到了這個事件,但寫在事件裏的異步請求爲何發送不成功?ios
緣由分析:這兩個問題無外乎兩個緣由:瀏覽器關閉事件未被觸發 和 異步請求發送失敗。web
緣由1:關閉瀏覽器時必定會觸發事件嗎?若是不必定,那什麼條件下才不觸發呢?ajax
與瀏覽器關閉事件相關事件有onunload和onbeforeunload兩個。區別在於onbeforeunload在onunload以前執行,它還能夠阻止onunload的執行。所以咱們着重關注onbeforeunload事件。簡單科普一下onbeforeunload事件。axios
當窗口即將被卸載(關閉)時,會觸發該事件.此時頁面文檔依然可見,且該事件的默認動做能夠被取消. 該函數應當返回一個字符串,當返回的字符串不爲null或者undefined時,彈出確認窗口讓用戶自行選擇是否關閉當前頁面。一些瀏覽器將該事件返回的字符串顯示在彈出窗上。promise
既然「當窗口即將被卸載(關閉)時,會觸發該事件「,那也就是說只要我關閉快就必定會觸發該事件嘍?然而當關閉瀏覽器時,未必必定會觸發onbeforeunload事件。MDN上關於這個事件的觸發條件是這樣描述的。瀏覽器
爲避免意外彈出窗口,除非頁面已與之交互,不然瀏覽器可能不會顯示在beforeunload事件中建立的提示,甚至根本不會顯示它們。服務器
那何時算是非與之交互呢?這裏舉個例子,一個頁面連着刷新兩次,第二次刷新時,就認爲非與之交互,就不會觸發onbeforeunload事件。,同時對於觸發條件,各個瀏覽器之間也存在差別。具體差別彙總表以下:app
說明一下,瀏覽器關閉事件(onbeforeunload)裏已經不能夠自定義彈出窗信息了。MDN中明確寫道:異步
一些瀏覽器將該事件返回的字符串顯示在彈出窗上。但從Firefox 四、 Chrome 5一、Opera 38 和Safari 9.1開始,通用確認信息代替事件返回的字符串。函數
緣由2:異步請求發送失敗了嗎?
必定失敗。緣由發送異步請求後,隨即關閉了瀏覽器,這時候此次請求的」三次握手」的」第三次握手」,客戶主機便不會響應服務器主機,這也就成了一個失敗的請求。如圖所示。
第三次握手失敗
那麼有什麼解決辦法嗎?
a) 頁面延遲幾秒後再關閉,體驗糟糕。
b) XMLHttpRequest規範中禁止在這個事件處理器中同步調用接口。
使用
XMLHttpRequest
發送同步請求的方式已經計劃從規範中刪除,再也不建議開發者使用。
這個時候不熟悉XMLHttpRequest的同窗也許會問:等一下,個人代碼里根本就沒有XMLHttpRequest這個對象,因此他的規範憑什麼約束我?
相信你項目裏調用接口時已經用到了ajax庫,或者axios庫。其實現有的ajax庫都是對XMLHTTPRequest對象的一種封裝,而axios是經過promise實現對ajax技術的一種封裝,這樣一來一切都說得通了。原來咱們都在直接或者間接的使用着XMLHttpRequest對象。
2.Fetch 的keepalive屬性
Fetch API提供了一套健壯的與服務器端交互的方式,提供了跨越不一樣平臺 API 的一致接口。它提供了一個keepalive屬性,保證無論發送請求的頁面關閉與否,請求都會持續直到結束。不過上傳數據的限制是64 KB。寫法以下:
window.addEventListener(‘onbeforeunload’, { fetch('/siteAnalytics', { method: 'POST', body: getStatistics(), keepalive: true }); }
那經過Fetch API調用的接口如何添加頭信息呢?以添加token爲例,如下代碼親測有效。
window.addEventListener(‘onbeforeunload’, { fetch('/siteAnalytics', { method: 'POST', body: 'id=' + id + '&name=' + name + '&age=' + age, headers: { 'Content-Type': 'application/x-www-form-urlencoded', token:’ myToken’ }, keepalive: true }); }
3.SendBeacon()
SendBeacon() 方法可用於經過HTTP將少許數據異步傳輸到Web服務器。該方法底層的使用的是 Fetch API,這樣就能明白爲何它也有少許數據(64 KB)的上傳數據限制,也能明白爲何它還能在頁面卸載後繼續請求。它的主要優勢是簡單,只要用一行代碼就能搞定。
window.addEventListener('unload', { navigator.sendBeacon('/siteAnalytics', getStatistics()); }
總結一下,對於瀏覽器關閉事件,若是咱們與頁面未發生交互,那麼當窗口即將被卸載(關閉)時便不會觸發onbeforeunload事件;同時一些主流瀏覽器,從某個版本開始,也不容許咱們自定義彈窗信息來給予用戶友好提示了;若是想在該事件中發送請求,相對於使用XMLHttpRequest對象來講,fetch API或者sendBeacon()或是更好的選擇。