微軟的開發(fā)周期中很重要的一塊是調(diào)整產(chǎn)品的性能。性能調(diào)整也是開發(fā)者應(yīng)當(dāng)留心的關(guān)鍵部分之一。 經(jīng)過多年發(fā)展,業(yè)界對于如何優(yōu)化Win32程序性能已經(jīng)有非常多的了解。 現(xiàn)在開發(fā)者遇到的問題之一是不太清楚是什么導(dǎo)致DTHML和HTML頁面運(yùn)行快或者慢。當(dāng)然,有一些很簡單的方法——比如不要使用2MB大的圖片。我們曾經(jīng)使用過另外一些有趣的技巧提高了DHTML頁面的性能,希望它們能幫助你改善自己的頁面性能。 這里我使用了一個建立Table的程序例子。其中用document.createElement()和element.insertBefore()方法創(chuàng)建了1000行(Row)的表(Table)。每行有一列(Cell)。Cell中包含的內(nèi)容稱為"Text"。這段代碼能有多糟呢?這么小的程序又能有多大調(diào)整余地呢?請看介紹。 一開始我寫了一段自認(rèn)為會很快的程序,我盡量避免一些低級問題----像沒有顯式定義變量、或者在一個頁面中同時使用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內(nèi)存/NT4.0/IE5.0的機(jī)器上運(yùn)行這段程序。頁面從本機(jī)上裝載。從開始裝載頁面到頁面完全安靜下來(所有的事件均已經(jīng)運(yùn)行,屏幕顯示完成)的時間為2328毫秒,這也是本次測試的基線(我稱之為Test1)。 這個頁面中,一個很耗時的操作是頻繁引用全局對象,如“document”、“body”、“window”等。引用所有這些類似的全局變量遠(yuǎn)比引用一個本地變量代價高昂。 因此我作了第一次改進(jìn)嘗試:緩存(Cache)document.body 到本地變量“theBody”中: 增加了如下代碼: var theBody = document.body;
然后修改這一行: document.body.insertBefore(tbl, null);
將之改為: theBody.insertBefore(tbl, null);
這次修改并沒有太大影響到整體時間,它只縮短了3 ms。但它已經(jīng)表明,如果在循環(huán)中也有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>
此次運(yùn)行時間只有2100ms,節(jié)約了大約10%的時間。使用本地變量而不是直接引用document對象平均每次節(jié)約了0.4毫秒。 一個常用的優(yōu)化性能的方法是:當(dāng)腳本不需要立即運(yùn)行時,在<SCRIPT>標(biāo)簽中設(shè)置“defer”屬性。 (立即腳本沒有被包含在一個function塊中,因此會在加載過程中執(zhí)行。) 設(shè)置“defer”屬性后,IE就不必等待該腳本裝載和執(zhí)行完畢。這樣頁面加載會更快。一般來說,這也表明立即腳本最好放在function塊中,并在document或者body對象的onload 句柄中處理該函數(shù)。在有一些腳本需要依賴用戶操作而執(zhí)行時----例如點(diǎn)擊按鈕,或者移動鼠標(biāo)到某個區(qū)域----使用該屬性非常有用。但當(dāng)有一些腳本需要在頁面加載過程中或加載完成后執(zhí)行,使用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>
這次測試的時間為2043 ms。相對基線測試提高了12%,比上次測試提高了2.5%。 下面我們談到的一個改進(jìn)方法非常有用,當(dāng)然也稍微麻煩一點(diǎn)。當(dāng)需要創(chuàng)建元素然后將其插入樹狀的結(jié)構(gòu)中時,將其直接插入到主干中效率更高----而不是首先將其插入大的子樹,然后再將大的子樹插入主干。例如,如果你創(chuàng)建一個每行有一列、列中有一些文字的表,你可以這樣做: 1. 創(chuàng)建<TR> 2. 創(chuàng)建<TD> 3. 創(chuàng)建TextNode節(jié)點(diǎn) 4. 將TextNode 插入<TD> 5. 將<TD> 插入到 <TR> 6. 將<TR>插入到TBODY 當(dāng)它要比下面的方法慢一些: 1. 創(chuàng)建<TR> 2. 創(chuàng)建<TD> 3. 創(chuàng)建TextNode 4. 將<TR> 插入到TBODY 5. 將<TD> 插入到<TR> 6. 將TextNode插入到<TD> 上面的四次測試使用的都是前一種方法。我們用后一種方法進(jìn)行第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>
Test5只需1649ms。這比上次測試提高了25%,比基線快了幾乎30%。 隨后的修改是使用了預(yù)制的樣式表。使用了預(yù)制樣式表的表格列寬或者是通過<COL>標(biāo)簽設(shè)置,沒有<COL>標(biāo)簽時,每列的寬度均勻分布。因為不需要對每一列重新計算大小等,使用樣式表實際上提高了性能,尤其當(dāng)表格中的列數(shù)很多時。 增加樣式表(CSS)的代碼非常簡單,如下: tbl.style.tableLayout = "fixed";
因為我們測試中的表格只有一列,這種改變只提高了頁面1.6%的性能。如果有更多的列,性能增加會更多。 最后兩次測試改變了將文字插入到表格中的方法。前面的測試中,我們都先創(chuàng)建一個TextNode ,然后將其插入到TD中。在Test7中, 取而代之,我們通過innerText 指定包含的文字。修改的代碼是: td.innerText = "Text";
令人驚奇的是,這次修改產(chǎn)生的差異很大----比上次提高了9%的性能,比最初總共提高了36%的性能。時間從最初的2323ms到最后的1473ms。 現(xiàn)在,幾乎人人都知道使用element.innerHTML 非常慢. 為了看看究竟它如何慢,我做了最后一次測試:使用 innerHTML替代innerText插入文字。這大大降低了性能。時間達(dá)到3375ms,比上次測試慢了80%,比基線測試慢了45%。顯然,innerHTML是非常耗時的。 下表總結(jié)了各次測試及其結(jié)果:http://msdn.microsoft.com/library/en-us/dndude/html/results2.asp 調(diào)整HTML頁面性能類似于調(diào)整Win32應(yīng)用程序性能;需要知道什么慢,什么快。希望這些方法能幫你提高頁面性能。 |
|