讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議107:應理清HTML DOM加載流程 >

建議107:應理清HTML DOM加載流程

HTML DOM文檔加載是按順序執行的,這與瀏覽器的渲染方式有關係,一般瀏覽器渲染操作的順序如下:

第1步,解析HTML結構。

第2步,加載外部腳本和樣式表文件。

第3步,解析並執行腳本代碼。

第4步,構造HTML DOM模型。

第5步,加載圖片等外部文件。

第6步,頁面加載完畢。

例如,下面這個簡單的DOM文檔。


<html>

<head>

<title>網頁標題</title>

<style type="text/css">

body{font-size:12px;}

</style>

<link href="style.css"rel="stylesheet"type="text/css"media="all">

<script src="js.js"type="text/javascript"></script>

</head>

<body>

<p>

<script type="text/javascript">

function f1{}

</script>

<img src="1.gif"/>

</p>

<script type="text/javascript">

function f2{}

</script>

</body>

</html>


這個文檔的加載和構造順序如下,所謂構造就是把對應的標籤元素添加到DOM文檔對像模型中。

html→head→title→#text(網頁標題)→style→加載樣式→解析樣式→link→加載外部樣式表文件→解析外部樣式→script→加載外部腳本文件→解析外部腳本→執行外部腳本→body→p→script→加載腳本→解析腳本→執行腳本→img→script→加載腳本→解析腳本→執行腳本→加載外部圖像文件→頁面初始化完畢。

通過上面的HTML DOM加載順序,可以看到網頁頭部的腳本(由外部文件加載)會在構造HTML DOM文檔結構之前執行,這就會導致執行腳本無法訪問文檔結構模型。所以,一般可執行腳本都放在頁面初始化事件處理函數中,這樣能夠確保完全加載完文檔之後再執行腳本。

但是,如果頁面中包含很多外部文件,如大量圖片、視頻、音頻、動畫等文件,可能會延遲腳本的執行時間。為了避免JavaScript腳本處於較長時間的等待,可以把需要執行的腳本分塊放在HTML文檔結構中間,這樣只要在構造DOM後執行到腳本所在結構位置,就會執行腳本。

這種方法雖然能夠提前執行腳本,但是不能夠保證腳本可以訪問該位置後面的文檔結構,因為這些文檔結構還沒有被構造。不過,如果在頁面最後一個元素之前嵌入腳本,就可以最早執行腳本,並能夠確保腳本可以訪問HTML文檔結構模型中所有元素。例如:


<html>

<head>

<title></title>

</head>

<body>

<!--文檔結構-->

<script language="javascript"type="text/javascript">

//JavaScript執行腳本</script>

</body>

</html>


上述方法容易破壞文檔的結構,使整個文檔看起來很混亂,不利於管理。可以利用一種間接的方法來實現文檔結構的有序顯示,當加載完DOM文檔後,也意味著Document對象的屬性加載完畢,這樣可以判斷Document對象的幾個重要方法,如果存在,則說明DOM已經加載完畢,否則說明DOM還在加載中。通過這種方法既不影響文檔結構,又可以快速捕捉到DOM加載的過程,實現的代碼如下:


function f{

if(document&&document.getElementsByTagName&&document.getElementById&&document.body){

clearInterval(timer);

//JavaScript執行腳本

}

}

var timer=setInterval(f,10);


在函數f中,首先判斷Document對象的幾個重要方法是否已經加載完畢,如果加載完畢,則說明DOM結構已經完成加載,執行預定的JavaScript腳本。為了能夠實時跟蹤加載過程,這裡設計了一個定時器,不斷調用函數f,以便快速、準確地判斷DOM加載狀態。如果DOM加載完畢,則清除定時器,並開始執行腳本。