加快 DHTML 的一組技巧(摘自MSDN)

 

加快 DHTML 的一組技巧

Mark Davis
Microsoft Corporation

摘要:本文說明了某些 DHTML 功能對性能的重大影響,並提供了一些提高 DHTML 頁面性能的技巧。

目錄

簡介
成批處理 DHTML 更改
使用 innerText
使用 DOM 添加單個元素
擴展 SELECT 元素中的選項
用 DOM 更新表
編寫一次,使用多次
請勿過多使用動態屬性
數據綁定很有效
不要在 document 對象中設置 expando 屬性
避免切換類和樣式規則
查找父項之前,先摺疊文本範圍
其他資料

簡介

動態 HTML (DHTML) 在 Microsoft® Internet Explorer 4.0 中的引入,使 Web 作者和開發人員可以使用新的編程模型。此後,Web 作者充分利用了這個強大的特性來提供動態內容、樣式和定位,使 Web 用戶得以體驗豐富的交互式功能。DHTML 的靈活性使得通常會有多種方式可以實現您的構思。理解 Internet Explorer 的 HTML 分析和顯示組件如何處理請求,可幫助您確定完成工作的最佳方法。本文介紹了某些 DHTML 功能對性能的重大影響,並提供了一些提高頁面性能的技巧。

成批處理 DHTML 更改

在 DHTML Web 頁面上,提高性能的最有效方法是改進對頁面上 HTML 內容的更改。有多種方法可以更新 Web 頁面,瞭解這一點非常重要。從客戶的反饋來看,Web 作者可以應用 HTML 文本塊,也可以通過使用 DHTML 對象模型(英文)或 W3C 文檔對象模型 (DOM)(英文)來訪問個別 HTML 元素。無論何時更改 HTML 內容,Internet Explorer 的 HTML 分析和顯示組件都必須重新組織該頁面的內部表現形式,重新計算文檔佈局和文檔流,並顯示這些變化。雖然實際性能由 Web 頁面的內容和您所作的更改決定,但是這些操作代價都比較大。如果您應用 HTML 文本塊,而不是個別訪問元素,則必須調用 HTML 分析器,這將導致額外的性能開銷。接受 HTML 文本的方法和屬性包括 insertAdjacentHTML(英文)和 pasteHTML(英文)方法,以及 innerHTML(英文)和 outerHTML(英文)屬性。

技巧 1:在一個腳本函數中對 HTML 內容進行更改。如果您的設計使用了多個事件處理程序(例如響應鼠標移動),則應集中進行更改。

HTML 分析和顯示組件的另一項重要事實是:一旦腳本返回控制(例如,當腳本事件處理函數退出時,或者當調用 setTimeout(英文)等方法時),該組件將重新計算佈局並顯示 Web 頁面。現在,您已經瞭解 Internet Explorer 如何處理變化,下面將開始提高 Web 頁面的性能。

技巧 2:建立一個 HTML 字符串並對文檔進行一次更改,而不是進行多次更新。如果 HTML 內容不是必要的,可考慮使用 innerText(英文)屬性。

在以下示例中,速度較慢的方法每次設置 innerHTML 屬性時都調用 HTML 分析器。要提高性能,可以先建立一個字符串,然後將其分配給 innerHTML 屬性。

請顯示

慢:

 divUpdate.innerHTML = "";
 for ( var i=0; i<100; i++ )
 {
  divUpdate.innerHTML += "<SPAN>這是一個較慢的方法!</SPAN>";
 }

快:

 var str="";
 for ( var i=0; i<100; i++ )
 {
  str += "<SPAN>因爲使用字符串,此方法較快!</SPAN>";
 }
 divUpdate.innerHTML = str;

有關詳細信息,請參見動態內容(英文)。

使用 innerText

DHTML 對象模型通過 innerText(英文)屬性訪問 HTML 元素的文本內容,而 W3C DOM 則提供一個獨立的子文本節點。直接通過 innerText 屬性更新元素的內容,比調用 DOM createTextNode(英文)方法更快。

技巧 3:使用 innerText 屬性更新文本內容。

以下示例顯示瞭如何使用 innerText 屬性提高性能。

請顯示

慢:

 var node;
 for (var i=0; i<100; i++)
 {
  node = document.createElement( "SPAN" );
  node.appendChild(  document.createTextNode( "使用 createTextNode() ") );
  divUpdate.appendChild( node );
 }

快:

 var node;
 for (var i=0; i<100; i++)
 {
  node = document.createElement( "SPAN" );
  node.innerText = "使用 innerText 屬性";
  divUpdate.appendChild( node );
 }

使用 DOM 添加單個元素

如前所述,應用 HTML 文本的訪問方法將導致調用 HTML 分析器,從而會降低性能。因此,使用 createElement(英文)和 insertAdjacentElement(英文)方法添加元素比調用一次 insertAdjacentHTML 方法快。

技巧 4:調用 createElementinsertAdjacentElement 方法比調用 insertAdjacentHTML 方法快。

成批處理 DHTML 更新並調用一次 insertAdjacentHTML 方法可以提高性能,但是有時直接通過 DOM 創建元素效率更高。在下面的方案中,您可以嘗試一下這兩種方法並確定哪一種更快。

請顯示

慢:

 for (var i=0; i<100; i++)
  {
  divUpdate.insertAdjacentHTML( "beforeEnd", "<SPAN> 使用 insertAdjacentHTML() </SPAN>" );
 }

快:

 var node;
 for (var i=0; i<100; i++)
 {
  node = document.createElement( "SPAN" );
  node.innerText = " 使用 insertAdjacentElement() ";
  divUpdate.insertAdjacentElement( "beforeEnd", node );
 }

擴展 SELECT 元素中的選項

對於上一條使用 HTML 文本方法的規則來說,將大量 OPTION(英文)元素添加到 SELECT(英文)中的情況是一種例外。這時候,使用 innerHTML 屬性比調用 createElement 方法訪問選項集合效率更高。

技巧 5:使用 innerHTML 將大量選項添加到 SELECT 元素中。

使用字符串連接操作來建立 SELECT 元素的 HTML 文本,然後使用此技巧設置 innerHTML 屬性。對於數量特別大的選項,字符串連接操作也會影響性能。在此情況下,請建立一個數組並調用 Microsoft JScript® join(英文)方法來執行 OPTION 元素 HTML 文本的最終連接。

請顯示

慢:

 var opt;
 divUpdate.innerHTML = "<SELECT ID='selUpdate'></SELECT>";
 for (var i=0; i<1000; i++)
 {
  opt = document.createElement( "OPTION" );
  selUpdate.options.add( opt );
  opt.innerText = "第 " + i + " 項";
 }

快:

 var str="<SELECT ID='selUpdate'>";
 for (var i=0; i<1000; i++)
 {
  str += "<OPTION>第 " + i + " 項</OPTION>";
 }
 str += "</SELECT>";
 divUpdate.innerHTML = str;

更快:

 var arr = new Array(1000);
 for (var i=0; i<1000; i++)
 {
  arr[i] = "<OPTION>第 " + i + " 項</OPTION>";
 }
 divUpdate.innerHTML = "<SELECT ID='selUpdate'>" + arr.join() + "</SELECT>";

用 DOM 更新表

使用 DOM 方法插入表的行和單元格比使用 insertRow(英文)和 insertCell(英文)方法(DHTML table 對象模型的一部分)效率更高。尤其在創建大的表時,效率上的差別更加明顯。

技巧 6:使用 DOM 方法建立大表。

請顯示

慢:

 var row;
 var cell;
 for (var i=0; i<100; i++)
 {
  row = tblUpdate.insertRow();
  for (var j=0; j<10; j++)
  {
    cell = row.insertCell();
    cell.innerText = "第 " + i + " 行,第 " + j + " 單元格";
  }
 }

快:

 var row;
 var cell;
 var tbody = tblUpdate.childNodes[0];
 tblUpdate.appendChild( tbody );
 for (var i=0; i<100; i++)
 {
  row = document.createElement( "TR" );
  tbody.appendChild( row );
  for (var j=0; j<10; j++)
  {
    cell = document.createElement( "TD" );
    row.appendChild( cell );
    cell.innerText = "第 " + i + " 行,第 " + j + " 單元格";
  }
 }

編寫一次,使用多次

如果您的 Web 站點使用腳本來執行一些常用操作,可以考慮將這些功能放到獨立的文件中,以便可以由多個 Web 頁面重複使用。這樣做,不僅可以改善代碼的維護性,而且使該腳本文件保留在瀏覽器的緩存中,從而只需要在用戶訪問站點時向本地下載一次。將常用的樣式規則放在獨立的文件中也可以得到同樣的好處。

技巧 7:通過將常用代碼放到行爲或獨立文件中來重用腳本。

要更好地利用腳本重用功能,請將常用的腳本操作放到 DHTML 附加代碼或元素行爲(英文)中。行爲提供了一個有效的方法,用於重用腳本和建立從 HTML 訪問的組件,並使您可用自己的對象、方法、屬性和事件來擴展 DHTML 對象模型。對於未使用 viewlink(英文)功能的行爲,可以考慮使用 Internet Explorer 5.5 中的 lightweight(英文)行爲特性進行更有效的代碼封裝。另外,如果您的腳本代碼在一個 SCRIPT(英文)塊中,會獲得更高的性能。

請勿過多使用動態屬性

動態屬性(英文)爲 Web 作者提供了一種將表達式用作屬性值的方法。表達式在運行時計算,其結果值將應用於屬性。這是一個強大的特性。此特性可用於減少頁面上的腳本數量,但是因爲必須定時重算表達式,而且該表達式經常與其他屬性值相關,所以它會對性能帶來消極的影響。這種情況對定位屬性尤其明顯。

技巧 8:限制使用動態屬性。

數據綁定很有效

數據綁定(英文)是一個強大的功能,它使您可以將數據庫查詢的結果或 XML 數據島(英文)的內容,綁定至 Web 頁面上的 HTML 元素。您無需返回服務器提取數據,就可以提供數據排序和過濾功能,以及不同的數據視圖。設想一個 Web 頁面可以將公司的數據顯示爲折線圖、條形圖或餅圖,還具有將數據按辦公室、產品或銷售階段排序的按鈕,而且所有這些功能只需要訪問一次服務器就能實現。

技巧 9:使用數據綁定來提供豐富的客戶端數據視圖。

有關數據綁定的詳細信息,請參見以下文章:

不要在 document 對象中設置 expando 屬性

expando(英文)屬性可以添加至任何對象。此屬性非常有用,它可以存儲當前 Wed 頁面內的信息,並提供了另一種擴展 DHTML 對象模型的方法。例如,您可以給 DHTML 元素指定一個 clicked 屬性,用此屬性提示用戶已經單擊了哪一個元素。在引發事件時,也可以使用 expando 屬性,向事件處理函數提供更多的上下文信息。無論您如何使用 expando 屬性,切記不要在 document(英文)對象上設置它們。如果您這樣做,則當您訪問該屬性時,文檔必須執行額外的重算操作。

技巧 10:window(英文)對象上設置 expando 屬性。

請顯示

慢:

for (var i=0; i<1000; i++)
 {
  var tmp;
  window.document.myProperty = "第 " + i + " 項";
  tmp = window.document.myProperty;
 }

快:

for (var i=0; i<1000; i++)
 {
  var tmp;
  window.myProperty = "第 " + i + " 項";
  tmp = window.myProperty;
 }

避免切換類和樣式規則

切換類和樣式規則是一種代價非常高的操作,需要重新計算並調整整個文檔的佈局。如果您的 Web 站點使用樣式表來提供內容的備用視圖,可以考慮直接修改要更改的元素的 style(英文)對象,而不是修改元素的 className(英文)屬性或與類關聯的 styleSheet(英文)對象。

技巧 11:在更改內容的外觀時,直接修改 style 對象。

查找父項之前,先摺疊文本範圍

TextRange(英文)對象表示用戶選定或從 HTML 元素中檢索的一個文本區域,例如 BODY(英文)。通過調用 parentElement(英文)方法,可以標識文本範圍的父項。對於複雜的文本範圍,在調用 parentElement 方法之前,先調用 collapse(英文)方法效率會更高。

技巧 12:在訪問 parentElement 方法之前,先摺疊文本範圍。

有關詳細信息,請參見 使用 TextRange 對象(英文)。

其他資料

有關提高性能的其他技巧來源,請參見以下文章:


Mark Davis 是 Internet Explorer SDK 文檔組的軟件設計工程師。他不懈地探索 Internet Explorer 的最新技術,不過有時也會到西北部去放鬆一下。

發佈了40 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章