對前端同窗而言,loade,unload,DOMContentLoaded等頁面加載過程當中會觸發的事件確定是都接觸過,不過要是具體問各個事件的區別,我就不是那麼能清晰的解答上來的了。正好剛剛在無阻塞腳本那看到了DOMContentLoaded事件,就來翻翻具體文檔詳細看一下各個事件吧。常言道溫故而知新,讓咱們一塊兒回頭看一下javascript
先看下各個事件的觸發時機(參考自MDN)css
當初始html文檔徹底加載並解析以後觸發,無需等待樣式、圖片、子frame結束。做爲明顯的對比,load事件只有一個頁面徹底被加載時才觸發。改用DOMContentLoaded的地方經常是load來代替,這是錯誤的。 tips: 有許多通用和獨立的庫提供跨瀏覽器方法來檢測 DOM 是否已準備就緒即ready事件,後面咱們能夠看下zepto的實現html
當一個資源及其依賴的資源結束加載時觸發。從這裏能夠看到須要等待依賴資源的結束加載。前端
document有readyState屬性來描述document的loading狀態,readyState的改變會觸發readystatechange事件.html5
loadingjava
文檔仍然在加載jquery
interactiveapi
文檔結束加載而且被解析,可是想圖片,樣式,frame之類的子資源仍在加載瀏覽器
completedom
文檔和子資源已經結束加載,該狀態代表將要觸發load事件。
所以,咱們一樣可使用該事件來判斷dom的加載狀態。
但並不是全部對象都會經歷 readyState 的這幾個階段,有時候須要
當瀏覽器窗口,文檔或其資源將要卸載時,會觸發beforeunload事件。這個文檔是依然可見的,而且這個事件在這一刻是能夠取消的.
若是處理函數爲Event對象的returnValue屬性賦值非空字符串,瀏覽器會彈出一個對話框,來詢問用戶是否肯定要離開當前頁面(以下示例)。有些瀏覽器會將返回的字符串展現在彈框裏,但有些其餘瀏覽器只展現它們自定義的信息。沒有賦值時,該事件不作任何響應。 tip:2011年5月25號起,html5中指出,該事件中調用window.alert(), window.confirm(), and window.prompt()方法將會被忽略。
當文檔或者一個子資源將要被卸載時,在beforeunload 、pagehide兩個事件以後觸發。
文檔會處於一個特定狀態。
從上面的定義,咱們能夠得出一個比較清晰的順序了。
頁面加載開始,首先確定是先發出加載資源的請求,加載未完成以前,不觸發任何事件。
document加載結束並解析,此時css等其餘資源未加載完成。
此時readyState爲'interactive',代表document已經load並解析完成,觸發 readystatechange,而後觸發DOMContentLoaded(在大多數瀏覽器上的表現如此)。捎帶提一句,此時,加載完成且帶有defer標記的腳本,會按順序開始執行。
css、img等子資源加載完成以後
此時觸發window.load事件
點擊關閉標籤或者刷新時,會依次觸發beforeunload、unload事件。
可能概念看的有點枯燥,仍是看下代碼比較清晰。你們能夠看下,下面的代碼會依次輸出什麼。
<!DOCTYPE html>
<html>
<head>
<title>文檔加載事件</title>
<script> document.addEventListener("DOMContentLoaded", function (event) { console.log("初始DOM 加載並解析"); }); window.addEventListener("load", function (event) { console.log("window 全部資源加載完成"); }); document.onreadystatechange = function () { console.log(document.readyState) if (document.readyState === "complete") { console.log('初始DOM,加載解析完成') } } window.addEventListener("beforeunload", function (event) { console.log('即將關閉') event.returnValue = "\o/"; }); window.addEventListener('unload', function (event) { console.log('即將關閉1'); }); </script>
<link rel="stylesheet" href="./test.css">
</head>
<body>
<div id="root">dom事件</div>
<script src="./index.js"></script>
</body>
</html>
複製代碼
依次輸出以下:
interactive //(index):15
初始DOM 加載並解析 //(index):8
complet//(index):15
初始DOM,加載解析完成//(index):17
window 全部資源加載完成//(index):11
//點擊關閉按鈕
即將關閉
即將關閉2
複製代碼
像jquery、zepto等類庫中都有document一個ready方法,來確保咱們的操做在初始dom加載以後進行,原生dom定義裏是沒有這個api的,是大牛們封裝了一下判斷的過程,提供咱們以便利。
有了前面的例子,讓咱們猜一下他們是怎麼實現的。
ready對應的狀態是初始化dom已經加載完成,咱們來看一下什麼狀況下對應該狀況。
有下面幾個狀態,complete、interactive 還有一個DOMContentLoaded也是初始dom加載完成,固然還有load事件,顯然這裏不會用到它,相對其餘狀態而言有點太晚了。
肯定觸發條件以後,下面的實現就簡單了,判斷就好了。
以zepto爲例,咱們看下實現:
//聲明變量,不僅使用interactive,是由於前面提到這些狀態不必定所有出現
readyRE = /complete|loaded|interactive/
ready: function(callback){
// need to check if document.body exists for IE as that browser reports
// document ready when it hasn't yet created the body element
if (readyRE.test(document.readyState) && document.body) callback($)
else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
return this
}
複製代碼
至此,介紹就結束了。對我而言,明瞭原來不太清楚的概念,但願對你們也有所幫助。
評論區中有同窗提到DOMContentLoaded時機的問題,即css 沒有加載完成,應該不會觸發 DOMContentLoaded。
這個問題可能會存在,舉個例子:
<div id="example-root">測試DOMContentLoaded 與css</div>
//隨手拿了一段css
<link rel="stylesheet" href="https://m.jb51.net/skin/mobile2017/css/common.css">
<script> document.addEventListener('DOMContentLoaded', function () { alert('DOMContentLoaded 觸發'); }); </script>
複製代碼
此時能夠看到觸發時,確實是css已經加載完成。 可是先不要忙着下結論,代碼換一下順序:
<div id="example-root">測試DOMContentLoaded 與css</div>
<script> document.addEventListener('DOMContentLoaded', function () { alert('DOMContentLoaded 觸發'); }); </script>
//隨手拿了一段css
<link rel="stylesheet" href="https://m.jb51.net/skin/mobile2017/css/common.css">
複製代碼
這時候能夠看到,觸發DOMContentLoaded時,css依舊處於pending狀態 若是會等待css的完成,顯然此時css應該加載完成了。
DOMContentLoaded觸發確實不會等待css加載完成的。上述現象的出現不是DOMContentLoaded時機的問題,是js執行順序問題。 js監聽事件的時候,css已經加載完成了,因此給人一種錯覺。