標籤:
一、載入
1. 依據HTML 4規範,script標籤可以放置在head和body標籤中的任意位置
2. 下載js指令碼會阻塞其他分頁檔下載,所以應儘可能將script標籤放置在body底部
3. HTML 4為script標籤增加了一個defer屬性,表明順延強制,但這並不是標準做法
4. 將多個script合并後壓縮,放置在body標籤底部,是引入多個外鏈javascript檔案的最佳實務
5. 通過動態建立標籤,可以非同步引入js檔案,代碼如下:
1 function loadScript(url, callback) { 2 3 var script = document.createElement(‘script‘) 4 script.type = ‘text/javascript‘ 5 6 // IE 7 if (script.readyState) { 8 script.onreadystatechange = function() { 9 if (script.readyState == ‘loaded‘ || script.readyState == ‘complete‘) {10 script.onreadystatechange = null11 callback()12 }13 }14 15 // other browser16 } else {17 script.onload = function() {18 callback()19 }20 }21 22 script.src = url23 document.getElementByTagName(‘head‘)[0].appendChild(script)24 }
6.使用xhr對象,同樣可以非同步引入js。與上面不同的是,你可以獲得準確的載入進度,並且,指令碼並不是一下載好就執行(取決於script標籤添加到頁面中的時間)
1 var xhr = new XMLHttpRequest() 2 3 xhr.open(‘get‘, ‘file.js‘, true) 4 xhr.onreadystatechange = function() { 5 6 if (xhr.readyState == 4) { 7 if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { 8 9 var script = document.createElement(‘script‘)10 11 script.type = ‘text/javascript‘12 script.text = xhr.responseText13 14 document.body.appendChild(script)15 }16 }17 }
二、資料
1. javascript資料類型:直接量、變數、數組、對象
2. 直接量和局部變數的訪問速度優於數組項和對象成員,變數訪問效能與範圍嵌套有直接關係
3. 閉包比非閉包函數需要更多記憶體開銷(變數的生命週期延長,並且最後不一定能釋放)
4. 使用hasOwnProperty只對執行個體進行尋找,而使用for in遍曆對象成員可以訪問prototype
5. 每次使用 "." 操作符時,會導致javascript引擎搜尋所有對象成員,對象成員嵌套越深,速度越慢。尤其是當訪問的屬性(方法)在原型鏈中時
6. 使用 "." 操作符,在safari下會比[key]更快,但[key]的寫法更通用(屬性為保留字)
7. 命名空間是導致頻繁訪問嵌套屬性的起因之一,對命名空間進行緩衝,可以有效減少對象訪問次數
1 // 對命名空間進行緩衝2 var load = ME.core.load3 4 // 對resource.length進行緩衝,避免每次遍曆都訪問resource5 for (var i = 0, length = resource.length; i < length; i++) {6 7 load.LoadResource(resource[i].url)8 }
三、DOM
1. 文件物件模型(DOM)是一個語言無關的,用於操作XML和HTML文檔的應用程式介面
2. DOM和ECMAScript是兩個獨立的功能,當他們通過介面相互訪問,就會產生消耗。訪問DOM元素要被收取“過橋費”,修改元素則更為昂貴,因為它會導致瀏覽器重新計算頁面的幾何變化
3. 使用dom方式產生html(body.appendChild)與使用innerHTML效率大致相同,在舊版本瀏覽器上innerHTML更勝一籌
4. 在大多數瀏覽器上,複製節點(cloneNode)比產生節點(createElement)更有效率
5. HTML集合一直與文檔保持著連結,每次訪問時,都會重複執行查詢的過程,哪怕只是擷取集合裡的元素個數。以下方法和屬性會造成這種低效率情況
1 document.getElementsByName()2 document.getElementsByClassName()3 document.getElementsByTagName()4 5 document.images6 document.forms7 document.links8 document.forms[0].elements
6. 遍曆元素子節點,ie下使用nextSibling比childNodes更快
1 // nextSibling 2 function testNextSibling() { 3 var el = document.getElementById(‘father‘), 4 ch = el.firstChild, 5 name = ‘‘ 6 7 do { 8 name = ch.nodeName 9 10 } while(ch = ch.nextSibling)11 12 return name13 }14 15 // childNodes16 function testChildNodes() {17 var el = document.getElementById(‘father‘),18 ch = el.childNodes,19 len = ch.length,20 name = ‘‘21 22 for (var i = 0; i < len; i++) {23 name = ch[i].nodeName24 }25 26 return name27 }
7. 使用原生的querySelector和querySelectorAll將比遍曆獲得更好的效率(ie8+)
8. 當DOM的變化影響了幾何屬性(盒模型),其他元素的幾何屬性和位置也會因此受到影響(normal flow)。瀏覽器會使渲染樹種受到影響的部分失效,並重新構造渲染樹。這個過程稱為“重排”。完成重排後,瀏覽器會重新繪製受到影響的部分到螢幕中,這個過程稱為“重繪”。以下情況會發生重排:
- 添加或刪除可見的DOM元素
- 元素位置改變
- 元素盒模型改變(padding、margin、width、height、border)
- 內容改變,如文字或圖片路徑
- 頁面渲染器初始化
- 瀏覽器視窗尺寸改變
有些改動會觸發整個頁面的重排,例如,當捲軸出現時
9. 重排會產生計算消耗,多數瀏覽器會通過隊列化修改並批量執行來最佳化重排過程。擷取布局資訊的操作會導致列隊重新整理,比如以下方法:
- offsetTop,offsetLeft,offsetWidth,offsetHeight
- scrollTop,scrollLeft,scrollWidth,scrollHeight
- clientTop,clientLeft,clientWidth,clientHeight
- getComputedStyle()
在修改樣式的過程中最好避免使用上述屬性
10. 將多次改動合并為一次,可以大幅提高效率。另一種一次性修改樣式的方式是修改class屬性,這種方法更利於維護和複用,雖然可能帶來輕微效能影響(改變類時需要檢查級聯樣式)
11. 有三個方法可以使DOM脫離文檔流
- 隱藏元素,應用修改,重新顯示
- 使用文檔片段,在當前DOM樹外構建一個子樹,再拷貝迴文檔
- 將原始元素拷貝到一個脫離文檔的節點中,修改副本,再替換原始元素
12. 在IE 7-8上大範圍使用hover會降低響應速度
13. 通過事件委託可以減少事件的綁定數量,從而提升效率。通過子項目冒泡觸發父元素的事件,可能更加簡單和優雅
14. 將需要大量修改的DOM節點(動畫元素)設定為絕對位置,使其脫離文檔流以減少影響
Javascript效能最佳化(一)