DOMContentLoaded、readystatechange、load、ready詳談

對前端同窗而言,loade,unload,DOMContentLoaded等頁面加載過程當中會觸發的事件確定是都接觸過,不過要是具體問各個事件的區別,我就不是那麼能清晰的解答上來的了。正好剛剛在無阻塞腳本那看到了DOMContentLoaded事件,就來翻翻具體文檔詳細看一下各個事件吧。常言道溫故而知新,讓咱們一塊兒回頭看一下javascript

觸發時機

先看下各個事件的觸發時機(參考自MDN)css

DOMContentLoaded

當初始html文檔徹底加載並解析以後觸發,無需等待樣式、圖片、子frame結束。做爲明顯的對比,load事件只有一個頁面徹底被加載時才觸發。改用DOMContentLoaded的地方經常是load來代替,這是錯誤的。 tips: 有許多通用和獨立的庫提供跨瀏覽器方法來檢測 DOM 是否已準備就緒即ready事件,後面咱們能夠看下zepto的實現html

load

當一個資源及其依賴的資源結束加載時觸發。從這裏能夠看到須要等待依賴資源的結束加載。前端

readystatechange

document有readyState屬性來描述document的loading狀態,readyState的改變會觸發readystatechange事件.html5

  • loadingjava

    文檔仍然在加載jquery

  • interactiveapi

    文檔結束加載而且被解析,可是想圖片,樣式,frame之類的子資源仍在加載瀏覽器

  • completedom

    文檔和子資源已經結束加載,該狀態代表將要觸發load事件。

所以,咱們一樣可使用該事件來判斷dom的加載狀態。
但並不是全部對象都會經歷 readyState 的這幾個階段,有時候須要

beforeunload

當瀏覽器窗口,文檔或其資源將要卸載時,會觸發beforeunload事件。這個文檔是依然可見的,而且這個事件在這一刻是能夠取消的.
若是處理函數爲Event對象的returnValue屬性賦值非空字符串,瀏覽器會彈出一個對話框,來詢問用戶是否肯定要離開當前頁面(以下示例)。有些瀏覽器會將返回的字符串展現在彈框裏,但有些其餘瀏覽器只展現它們自定義的信息。沒有賦值時,該事件不作任何響應。 tip:2011年5月25號起,html5中指出,該事件中調用window.alert(), window.confirm(), and window.prompt()方法將會被忽略。

unload

當文檔或者一個子資源將要被卸載時,在beforeunload 、pagehide兩個事件以後觸發。
文檔會處於一個特定狀態。

  • 全部資源仍存在 (圖片, iframe 等.)
  • 對於終端用戶全部資源均不可見
  • 界面交互無效 (window.open, alert, confirm 等.)
  • 錯誤不會中止卸載文檔的過程

頁面加載中的執行順序

從上面的定義,咱們能夠得出一個比較清晰的順序了。

  1. 頁面加載開始,首先確定是先發出加載資源的請求,加載未完成以前,不觸發任何事件。

  2. document加載結束並解析,此時css等其餘資源未加載完成。

    此時readyState爲'interactive',代表document已經load並解析完成,觸發 readystatechange,而後觸發DOMContentLoaded(在大多數瀏覽器上的表現如此)。捎帶提一句,此時,加載完成且帶有defer標記的腳本,會按順序開始執行。

  3. css、img等子資源加載完成以後

    此時觸發window.load事件

  4. 點擊關閉標籤或者刷新時,會依次觸發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  
複製代碼

關於ready

像jquery、zepto等類庫中都有document一個ready方法,來確保咱們的操做在初始dom加載以後進行,原生dom定義裏是沒有這個api的,是大牛們封裝了一下判斷的過程,提供咱們以便利。
有了前面的例子,讓咱們猜一下他們是怎麼實現的。

  1. ready對應的狀態是初始化dom已經加載完成,咱們來看一下什麼狀況下對應該狀況。

    有下面幾個狀態,complete、interactive 還有一個DOMContentLoaded也是初始dom加載完成,固然還有load事件,顯然這裏不會用到它,相對其餘狀態而言有點太晚了。

  2. 肯定觸發條件以後,下面的實現就簡單了,判斷就好了。

以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已經加載完成了,因此給人一種錯覺。

相關文章
相關標籤/搜索