DOMContentLoaded、readystatechange、load、ready詳談


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

觸發時機

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

DOMContentLoaded

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

load

當一個資源及其依賴的資源結束加載時觸發。從這里可以看到需要等待依賴資源的結束加載。

readystatechange

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

  • loading

    文檔仍然在加載

  • interactive

    文檔結束加載並且被解析,但是想圖片,樣式,frame之類的子資源仍在加載

  • complete

    文檔和子資源已經結束加載,該狀態表明將要觸發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
    } 

至此,介紹就結束了。對我而言,明了原來不太清楚的概念,希望對大家也有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM