讀高性能JavaScript編程 第三章

来源:http://www.cnblogs.com/zhuwansu/archive/2016/12/06/6138542.html
-Advertisement-
Play Games

第三章 DOM Scripting dom 文檔對象模型 類似的還有 bom 瀏覽器對象模型 。 要使用一個 對象首先要知道該對象存在的位置,比如 document 對象 它並不是被定義在 ECMAScript 中而是 dom 中。所以 本來你每次訪問 document就很慢。 引用: 文檔對象模型 ...


第三章  DOM Scripting 

  1. 最小化 DOM 訪問,在 JavaScript 端做儘可能多的事情。 
  2.   在反覆訪問的地方使用局部變數存放 DOM 引用. 
  3. 小心地處理 HTML 集合,因為他們表現出“存在性”,總是對底層文檔重新查詢。將集合的 length 屬性緩
  4. 存到一個變數中,在迭代中使用這個變數。如果經常操作這個集合,可以將集合拷貝到數組中。
  5.    如果可能的話,使用速度更快的 API,諸如 querySelectorAll()和 firstElementChild。 
  6.    註意重繪和重排版;批量修改風格,離線操作 DOM 樹,緩存並減少對佈局信息的訪問。 
  7.   動畫中使用絕對坐標,使用拖放代理。 
  8.    使用事件托管技術最小化事件句柄數量。 
  9. 上面八條建議都是抄的。

dom 文檔對象模型 類似的還有 bom 瀏覽器對象模型 。

要使用一個 對象首先要知道該對象存在的位置,比如 document 對象 它並不是被定義在 ECMAScript 中而是 dom 中。所以 本來你每次訪問 document就很慢。

引用:

  文檔對象模型(DOM)是一個獨立於語言的,使用 XML和 HTML 文檔操作的應用程式介面(API)。
在瀏覽器中,主要與 HTML 文檔打交道,在網頁應用中檢索 XML 文檔也很常見。DOM APIs 主要用於訪
問這些文檔中的數據。

  儘管 DOM 是與語言無關的 API,在瀏覽器中的介面卻是以 JavaScript 實現的。客戶端大多數腳本程式

與文檔打交道,DOM 就成為 JavaScript 代碼日常行為中重要的組成部分。

  瀏覽器通常要求 DOM 實現和 JavaScript 實現保持相互獨立。 例如, 在 Internet Explorer中, 被稱為 JScript

的 JavaScript實現位於庫文件 jscript.dll中,而 DOM 實現位於另一個庫 mshtml.dll(內部代號 Trident)。

兩個獨立的部分以功能介面連接就會帶來性能損耗,這就是為什麼會有上面8條建議。

註意:

  1、html集合的存在性

eg:document.getElementsByName()  返回一個類數組對象,這個對象就是 HTML集合。

eg:

 // an accidentally infinite loop 
var alldivs = document.getElementsByTagName_r('div'); 
for (var i = 0; i < alldivs.length; i++) { 
  document.body.appendChild(document.createElement('div')) 
} 

    說明:這段代碼看上去只是簡單地倍增了頁面中 div元素的數量。它遍歷現有 div,每次創建一個新的 div並附

加到 body上面。但實際上這是個死迴圈,因為迴圈終止條件 alldivs.length 在每次迭代中都會增加,它反
映出底層文檔的當前狀態。

其實這裡還有第二個問題,如果迴圈里沒有做任何操作,這是一個正常的迴圈,但它還是存在性能問題,因為目標是一個HTML集合。

簡單說就是每次迴圈 都會訪問 length 屬性,而length屬性的值是通過查詢文檔的操作得到的。每獲取一次length都會重新查詢一次文檔,以保證獲取到的數據是最新的,上面有一個現成的例證。更要命的是查詢文檔這個操作是天生就慢的。原因就在上面,有一段話可以加深印象:

  一個很形象的比喻是把 DOM 看成一個島嶼,把 JavaScript(ECMAScript)看成另一個島嶼,兩者之間以一座收費橋連接(參見 John Hrvatin,微軟,MIX09,http://videos.visitmix.com/MIX09/T53F)。每次 ECMAScript 需要訪問 DOM 時,你需要過橋,交一次“過橋費”。

所以,在迴圈的時候 把 length緩存到一個變數里最好。

 

如果把 alldivs 複製到一個數組內 例如 :

 function toArray(coll) { 
  for (var i = 0, a = [], len = coll.length; i < len; i++) { 
    a[i] = coll[i]; 
  } 
  return a; 
} 

可以更優的解決問題,如果你需要在迴圈中多次操作item的話(建議4)。 同時 len = coll.length 這樣寫是非常值得學習的,但是在C#中就不曉得有沒有益了。

  2、使用速度更快的api,這是一種更優的替代解決方案 eg:  var elements = document.getElementById('menu').getElementsByTagName_r('a');  elements =

toArray(elements); 和 var elements = document.querySelectorAll('#menu a'); 
建議5:
這兩個函數都是 DOM 節點的屬性,所以你可以使用 document.querySelector('.myclass')來查詢整個文檔中的節點,或者使用 elref.querySelector('.myclass')在子樹中進行查詢,其中 elref是一個 DOM 元素的引用。

3、 重繪和重拍版引用原文的解釋:

  當瀏覽器下載完所有頁面 HTML標記,JavaScript,CSS,圖片之後,它解析文件並創建兩個內部數據
結構:    A DOM tree       表示頁面結構   A render tree  表示 DOM 節點如何顯示 。

  渲染樹中為每個需要顯示的 DOM 樹節點存放至少一個節點(隱藏 DOM 元素在渲染樹中沒有對應節
點)。渲染樹上的節點稱為“框”或者“盒”,符合 CSS 模型的定義,將頁面元素看作一個具有填充、邊距、
邊框和位置的盒。一旦 DOM 樹和渲染樹構造完畢,瀏覽器就可以顯示(繪製)頁面上的元素了。

  當 DOM 改變影響到元素的幾何屬性(寬和高)——例如改變了邊框寬度或在段落中添加文字,將發生
一系列後續動作——瀏覽器需要重新計算元素的幾何屬性,而且其他元素的幾何屬性和位置也會因此改變
受到影響。瀏覽器使渲染樹上受到影響的部分失效,然後重構渲染樹。這個過程被稱作重排版。重排版完
成時,瀏覽器在一個重繪進程中重新繪製屏幕上受影響的部分。

  不是所有的 DOM 改變都會影響幾何屬性。例如,改變一個元素的背景顏色不會影響它的寬度或高度。
在這種情況下,只需要重繪(不需要重排版),因為元素的佈局沒有改變。

 

例子:(有可能根本不會出現,只為分析問題使用)
 // setting and retrieving styles in succession 
var computed,     
tmp = '', 
    bodystyle = document.body.style; 
if (document.body.currentStyle) { // IE, Opera 
  computed = document.body.currentStyle; 
} else { // W3C 
  computed = document.defaultView.getComputedStyle(docume
} 
// inefficient way of modifying the same property 
// and retrieving style information right after 
bodystyle.color = 'red'; 
tmp = computed.backgroundColor; 
bodystyle.color = 'white'; 
tmp = computed.backgroundImage; 
bodystyle.color = 'green'; 
tmp = computed.backgroundAttachment; 

PK: 

bodystyle.color = 'red'; 
bodystyle.color = 'white'; 
bodystyle.color = 'green'; 
tmp = computed.backgroundColor; 
tmp = computed.backgroundImage; 
tmp = computed.backgroundAttachment; //winner
bodystyle.color 雖然和 computed.backgroundColor等三個屬性無關,但是 瀏覽器仍要刷新渲染隊列並重排版,註意computed被查詢了。(如果把computed緩存到變數里就不會有這種情況)
這也是為什麼 後者PK勝出了。
還有一種情況更加具有畫面感,
 var el = document.getElementById('mydiv'); 
el.style.borderLeft = '1px'; 
el.style.borderRight = '2px'; 
el.style.padding = '5px'; 

這段代碼使瀏覽器排版了三次。只不過速度比較快感官上只改變了一次,但是可以想象到繪製三次的畫面。

(註意:現在大多數瀏覽器都優化了這種情況,只排版一次。) 

如同下麵代碼一樣:

 var el = document.getElementById('mydiv'); 
el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;'; 

 el.style.cssText += '; border-left: 1px;';  //or

el.className = 'active'; //or

  離線dom 很好理解,就是在 操作dom的時候不產生 重繪、重排,操作完成後一次性 ‘提交’。

離線dom的三種方式: 1、隱藏 and 操作 and 顯示 eg:

 var ul = document.getElementById('mylist'); 
ul.style.display = 'none'; 
appendDataToElement(ul, data); 
ul.style.display = 'block'; 

2、創建並更新一個文檔片斷,然後附加或替換,eg:

 var fragment = document.createDocumentFragment(); 
appendDataToElement(fragment, data); 
document.getElementById('mylist').appendChild(fragment); 

3、製作副本,替換原節點eg:

 var old = document.getElementById('mylist'); 
var clone = old.cloneNode(true); 
appendDataToElement(clone, data); 
old.parentNode.replaceChild(clone, old); 

緩存並減少對佈局信息的訪問就是類似 於提取局部變數,只不過佈局信息這類數據的訪問影響比較大。

4、動畫

  1. 使用絕對坐標定位頁面動畫的元素,使它位於頁面佈局流之外。
  2. 比如一個擴大和縮小的動畫,當擴大使其覆蓋原有佈局,重繪這一部分而不會重排、重繪一大部分頁面。
  3. 動畫結束時,重新定位。 其他元素是一起被覆位的。

5、事件托管技術最小化事件句柄數量

這裡說自己的理解有可能是錯誤的,暫時先這樣理解了:

首先 每個事件都有三個階段: 

• Capturing
捕獲
• At target
到達目標
• Bubbling
冒泡

在onload(或DOMContentReady) 事件里  會讓 很多元素和很多事件句柄 掛接/附加 (attached) ,而 有一些掛接是不必的。比如說一些根本不會被點到的按鈕。

引用:

一個簡單而優雅的處理 DOM 事件的技術是事件托管。它基於這樣一個事實:事件逐層冒泡總能被父元
素捕獲。採用事件托管技術之後,你只需要在一個包裝元素上掛接一個句柄,用於處理子元素髮生的所有
事件。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.let命令的用法和var命令類似,但let命令聲明的變數只在let所在的代碼塊內有效 2.let命令不存“聲明提前”現象,因此變數一定要先聲明,後使用 3.只要當前塊級作用域記憶體在let命令,它所聲明的變數就綁定了這個塊級作用域,不再受外部的影響 4.let命令不允許在同一個作用域內,重覆聲明同 ...
  • 這篇博文主要講一下如何使用Phantomjs進行數據抓取,這裡面抓的網站是太平洋電腦網估價的內容。主要是對電腦筆記本以及他們的屬性進行抓取,然後在使用nodejs進行下載圖片和插入資料庫操作。 ...
  • 1.canvas元素基礎知識 (1)在頁面上放置canvas元素,相當於在頁面上放置一塊“畫布”,可以用Javascript編寫在其中進行繪畫的腳本。 (2)在頁面中放置canvas元素 eg: 如上程式,使用canvas和Javascript腳本繪製矩形,步驟如下: (1)取得canvas元素,用 ...
  • XML文件的約束:什麼叫約束呢?顧名思義,就是對xml文件的內容進行按照既定規則的限制。我們知道,因為xml文件的標簽是可以自定義的,而往往我們用xml文件都是為了表達一定的數據集合(即小型的資料庫),而眾所周知的,資料庫也是分類型的,如學生資料庫,就包含了一系列的諸如name,age,studen ...
  • 1.級聯select的操作,後一個select的值隨著前一個select選中值變化 2.獲取select選中項value值 3.獲取select選中項的文本text 4.設置select選中對應value值項、對應text文本項 ...
  • 續上一篇文章:vue2.0 開發實踐總結之入門篇 ,如果沒有看過的可以移步看一下。 本篇文章目錄如下: 1. vue 組件的說明和使用 2. vuex在實際開發中的使用 3. 開發實踐總結 1. vue 組件的說明和使用 一個組件實質上是一個擁有預定義選項的一個 Vue 實例 在header組件內部 ...
  • 個人開發包的目錄結構 開發步驟 註冊 "npmjs" 命令行添加user 註冊成功後,在命令行執行 依次填完回車。 whoami 上面的填寫完後,命令行輸入 說明成功了。 npm publish 最後發佈至npmjs上 出現下麵類似的版本號就成功了 index.js的編寫 安裝&使用 可能遇到的問題 ...
  • 一、盒子模型(Box Model) 盒子模型也有人稱為框模型,HTML中的多數元素都會在瀏覽器中生成一個矩形的區域,每個區域包含四個組成部分,從外向內依次是:外邊距(Margin)、邊框(Border)、內邊距(Padding)和內容(Content),其實盒子模型有兩種,分別是 ie 盒子模型和標 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...