微軟的開發週期中很重要的一塊是調整產品的效能。效能調整也是開發者應留心的關鍵部分之一。 經過多年發展,業界對於如何優化Win32程式效能已經有非常多的了解。
現在開發者遇到的問題之一是不太清楚是什麼導致DTHML和HTML頁面運行快或慢。當然,有一些很簡單的方法──例如不要使用2MB大的圖片。我們曾經使用過另外一些有趣的技巧提升了DHTML頁面的效能,希望它們能幫助你提升自己的頁面效能。
這裡我使用了一個建立Table的程式範例。其中用document.createElement()和element.insertBefore()方法建立了1000行(Row)的表(Table)。每行有一列(Cell)。 Cell中所包含的內容稱為"Text"。這段程式碼能有多糟呢?這麼小的程式又能有多大調整空間呢?請看介紹。
一開始我寫了一段自認為會很快的程序,我盡量避免一些低階問題----像沒有明確定義變數、或在一個頁面中同時使用VBScript和Javascript。程式如下:
<html>
<body>
<script>
var tbl, tbody, tr, td, text, i, max;
max = 1000;
tbl = document.createElement("TABLE");
tbl.border = "1";
tbody = document.createElement("TBODY");
tbl.insertBefore(tbody, null);
document.body.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = document.createElement("TR");
td = document.createElement("TD");
text = document.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>
在PII233/64MB記憶體/NT4.0/IE5.0的機器上執行這段程式。頁面從本機上裝載。從開始裝載頁面到頁面完全安靜下來(所有的事件均已經運行,螢幕顯示完成)的時間為2328毫秒,這也是本次測試的基線(我稱之為Test1)。
這個頁面中,一個很耗時的操作是頻繁引用全域對象,如「document」、「body」、「window」等。引用所有這些類似的全域變數遠比引用一個本地變數代價高昂。
因此我作了第一次改進嘗試:快取(Cache)document.body 到本地變數「theBody」:
增加瞭如下程式碼:
var theBody = document.body;
然後修改這一行:
document.body.insertBefore(tbl, null);
將之改為:
theBody.insertBefore(tbl, null);
View the second sample.
這次修改並沒有太大影響到整體時間,它只縮短了3 ms。但它已經表明,如果在循環中也有document.body物件而對其引用做出修改,帶來的好處將是可觀的。
隨後,我快取了document物件----在我們這個測試中,document物件共被引用了3002次。修改後程式碼如下:
<html>
<body>
<script>
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>
View the third sample.
這次運行時間只有2100ms,節省了大約10%的時間。使用本地變數而不是直接引用document物件平均每次節約了0.4毫秒。
一個常用的最佳化效能的方法是:當腳本不需要立即執行時,在<SCRIPT>標籤中設定「defer」屬性。 (立即腳本沒有被包含在一個function區塊中,因此會在載入過程中執行。) 設定「defer」屬性後,IE就不必等待該腳本裝載和執行完畢。這樣頁面載入會比較快。一般來說,這也表示立即腳本最好放在function區塊中,並在document或body物件的onload 句柄中處理該函數。在有一些腳本需要依賴使用者操作而執行時----例如點擊按鈕,或移動滑鼠到某個區域----使用該屬性非常有用。但當有一些腳本需要在頁面載入過程中或載入完成後執行,使用defer屬性得到的好處就不太大。
下面是使用了defer屬性修改後的程式碼版本:
<html>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
}
</script>
</body>
</html>
View the fourth sample.
這次測試的時間為2043 ms。相對基線測試提高了12%,比上次測試提高了2.5%。
下面我們談到的一個改進方法非常有用,當然也稍微麻煩一點。當需要創建元素然後將其插入樹狀的結構中時,將其直接插入到主幹中效率更高----而不是首先將其插入大的子樹,然後再將大的子樹插入主幹。例如,如果你建立一個每行有一列、列中有一些文字的表,你可以這樣做:
1. 建立<TR>
2. 建立<TD>
3. 建立TextNode節點
4. 將TextNode 插入<TD>
5 . 將<TD> 插入到<TR>
6. 將<TR>插入到TBODY
當它要比下面的方法慢一些:
1. 建立<TR>
2. 建立<TD>
3. 建立TextNode
4. 將<TR > 插入到TBODY
5. 將<TD> 插入到<TR>
6. 將TextNode插入到<TD>
上面的四次測試使用的都是前一種方法。我們用後一種方法進行第5次測試。程式碼如下:
<html>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
tbody.insertBefore(tr, null);
tr.insertBefore(td, null);
td.insertBefore(text, null);
}
}
</script>
</body>
</html>
View the fifth sample.
Test5只需1649ms。這比上次測試提高了25%,比基線快了幾乎30%。
隨後的修改是使用了預製的樣式表。使用了預製樣式表的表格列寬或透過<COL>標籤設置,沒有<COL>標籤時,每列的寬度均勻分佈。因為不需要對每一列重新計算大小等,使用樣式表實際上提高了效能,尤其當表格中的列數很多時。
增加樣式表(CSS)的程式碼非常簡單,如下:
tbl.style.tableLayout = "fixed";
View the sixth sample.
因為我們測試中的表格只有一列,這種改變只提高了頁面1.6%的效能。如果有更多的列,效能增加會更多。
最後兩次測試改變了將文字插入表格中的方法。在前面的測試中,我們都先建立一個TextNode ,然後將其插入到TD中。在Test7中, 取而代之,我們透過innerText 指定包含的文字。修改的程式碼是:
td.innerText = "Text";
View the seventh sample.
令人驚訝的是,這次修改產生的差異很大----比上次提高了9%的性能,比最初總共提高了36%的性能。時間從最初的2323ms到最後的1473ms。
現在,幾乎人人都知道使用element.innerHTML 非常慢. 為了看看它究竟如何慢,我做了最後一次測試:使用innerHTML取代innerText插入文字。這大大降低了性能。時間達到3375ms,比上次測試慢了80%,比基線測試慢了45%。顯然,innerHTML是非常耗時的。
調整HTML頁面效能類似於調整Win32應用程式效能;需要知道什麼慢,什麼快。希望這些方法能幫你提升頁面效能。