高性能的JavaScript

一、加快JavaScript文件的加載速度css

     默認狀況下,瀏覽器在解析頁面時遇到JavaScript引用就會中止後續的HTML代碼解析,直到等待JavaScript代碼文件下載和運行完成後才繼續解析剩餘的HTML代碼。推薦的作法是儘可能將JavaScript代碼的引用放置在<body>的底部。數組

    相比把腳本引用放置於頁面底部的方式或動態建立script元素,給<script>設置defer和async屬性的方式更優雅,它在兼顧代碼可讀性的同時也提升了代碼加載執行的性能。defer就是在告訴瀏覽器JavaScript代碼不會產生任何的頁面內容,所以瀏覽器能夠在加載此引用時繼續解析頁面後續的內容。async屬性則代表能夠以異步的方式加載和執行(不受限於順序)JavaScript代碼。瀏覽器

    還能夠按需加載JavaScript文件。按需加載的方式能更有效地減小初始加載的JavaScript代碼量。推薦使用成熟的JavaScript加載框架,例如HeadJS、RequireJS、LABjs等JavaScript模塊加載框架。緩存

二、養成良好的編碼習慣,提升代碼的運行速度性能優化

     在編寫JavaScript代碼時,首先是保證代碼的可讀性和可維護,在此前提下才是選用高性能的編碼方式。app

      嵌套循環時把大循環做爲內循環、儘可能避免循環內定義變量、在條件分支中建立只有在分支中才須要用到的對象、使用直接量代替對象、緩存計算結果減小重複計算等。框架

      1)少用for-in循環異步

         for-in循環提供了一種遍歷對象屬性的能力,但它的性能不好,應儘可能使用for循環代替。async

      2)謹慎使用eval函數

      3)正確使用數組

         在索引時,一個混合了多種類型的數組將比類型單一的數組慢不少。所以,應使用數組保存類型單一的數據,而在其餘狀況下使用對象。

      4)正確地內存回收

三、使用高性能的變量或屬性值讀取方式

     做用域就是變量或函數的做用範圍,JavaScript中最大的做用域就是全局做用域。最小的做用域是函數。

     多個函數嵌套定義時,就會造成做用域包含的關係,這個關係成爲做用域鏈。若一個函數在運行中遇到一個變量,就會從最近的做用域開始進行搜索,若是找到了就會使用這個變量,若是沒有找到則會進入外層的做用域中查找,如此反覆,直到找到此變量的定義,或者未找到而斷定變量未定義爲止。

     一個變量在做用域鏈上查找的層級越多則讀取的速度越慢,所以,函數中局部變量的訪問是最快的,全局變量的訪問是最慢的。爲了提升變量的讀取性能,最佳的實踐是儘可能減小變量訪問時在做用域鏈上查找的層級,最好將變量定義爲本做用域的局部變量,儘可能不要定義全局變量。若是頻繁地訪問一個外做用域的變量,最好是用一個局部變量保存外部變量

     另一個和做用域相關的性能損耗是with語句的使用。with表達式的使用也會造成一個做用域,無形中改變了上下文做用域鏈的深度。try-catch表達式的catch塊中也會產生一個做用域。所以,最好將catch塊中的處理交給一個函數,避免了在內部訪問外部域的變量。

     對象的屬性讀取也存在和變量讀取時相似的性能影響,讀取對象上的屬性值時會搜索對象的原型鏈。

     在JavaScript中,對象的構造函數中有一個名爲prototype的對象,即爲原型對象,這個對象上的屬性和方法是共享給全部實例對象的。因此說,實例對象上的屬性和方法來自於兩個地方:自身和對應的原型對象。由於原型對象自己也能夠是其餘構造函數的實例對象,因此原型對象中的屬性和方法也可能來自於其做爲做爲實例對象時對應的原型對象上。這就造成了一個由各原型對象組成的鏈條,成爲原型鏈。原型鏈的頂端是構造函數Object中名爲prototype的對象。

     查找對象上的屬性和方法,首先會查找自身是否存在此屬性或方法,若是未找到,則會繼續在原型鏈上查找,直到找到或未找到返回undefined值爲止。

function Person (name){ this.name=name; } Person.prototype= {location: 'china'}; var personA = new Person('name1'); var personB = new Person('name2'); alter (personA.location); //china
alter (personB.location);   //china

      在原型鏈上檢索的層級越多,性能越差,即便是讀取在對象上直接定義的屬性也比讀取局部變量慢。所以,若是在代碼中要頻繁取得某個對象的屬性值,尤爲是此屬性來自於對象上的原型對象上時,最佳的作法是把屬性值緩存在局部變量中,提升讀取對象屬性的性能。

for (var i = 0;i < numbers.length; i++){ numbers[i] *= 2; } //性能改進的方案
for (var i = 0,len = numbers.length; i < len; i++){ numbers[i] *= 2; }

四、高效地DOM操做

    文檔對象模型(DOM)是一個獨立於特定語言的應用程序接口。儘管DOM提供了豐富接口供外部調用,但DOM操做的代價很高,頁面性能優化的一個主要的關注點就是DOM操做的優化。DOM操做優化的整體原則是儘可能減小DOM操做。

    在瀏覽器中,DOM的實現和ECMAScript的實現是分離的。經過JavaScript代碼調用DOM接口,至關與兩個獨立模塊的交互。DOM操做對性能影響最大實際上是由於它致使了瀏覽器的重繪(repaint)和重排(reflow)。

    瀏覽器的渲染原理:從下載文檔到渲染頁面的過程當中,瀏覽器會經過解析HTML文檔來構建DOM樹,解析CSS產生CSS規則樹。JavaScript代碼在解析過程當中,可能會修改生成的DOM樹和CSS規則樹。以後根據DOM樹和CSS規則樹構建渲染樹,在這個過程當中,CSS會根據選擇器匹配HTML元素。渲染樹包括了每一個元素的大小、邊距等樣式屬性,渲染樹中不包括隱藏元素即head元素等不可見元素。最後瀏覽器根據元素的座標和大小來計算每一個元素的位置,並繪製這些元素到頁面上。

    重繪指的是頁面的某些部分要從新繪製,好比顏色或背景色的修改,元素的位置和尺寸並無改變;重排則是元素的位置或尺寸發生了改變,瀏覽器須要從新計算渲染樹,致使渲染樹的一部分或所有發生變化。重排的代價比重繪的代價高不少,重繪會影響部分的元素,而重排則有可能影響所有的元素。

   以下的操做會致使重繪或重排:

      1)增長、刪除和修改可見DOM元素。

      2)頁面初始化的渲染。

      3)移動DOM元素。

      4)修改CSS樣式,改變DOM元素的尺寸。

      5)DOM元素內容改變,使得尺寸被撐大。

      6)瀏覽器窗口尺寸改變。

      7)瀏覽器窗口滾動。

    在進行DOM操做時,遵循如下的最佳實踐來下降因爲重排或重繪帶來的影響:

       1)合併屢次的DOM操做爲單次的DOM操做

element.style.borderColor = '#f00'; element.style.borderStyle = 'solid'; element.style.borderWidth = '1px';
//優化方案1
element.style.cssText += 'border: 1px solid #f00;'; //優化方案2
element.className += 'empty'; //HTML5:element.classList.add('empty'); 

         2)把DOM元素離線或隱藏後修改

            對脫離了頁面佈局流的DOM元素操做就不會致使頁面的性能問題。

            大批量修改DOM元素,具體的方式主要有如下3種:

              (1)使用文檔片斷

                  文檔片斷是一個輕量級的document對象,並不會和特定的頁面關聯。

var fragment = docment.createDocmentFragment (); //大量基於fragment的DOM操做
... docment.getElementById('myElement').appendChild(fragment);

              (2)經過設置DOM元素的display樣式爲none來隱藏元素

 var myElement = document.getElementById('myElement'); myElenment.style.display = 'none'; //一些基於myElement的DOM操做
 ... myElement.style.display = 'block';

                 (3)克隆DOM元素到內存中

 var old = document.getElementById('myElement'); var clone = old.cloneNode(true); //一些基於clone的DOM操做
 ... old.parentNode.replaceChild(clone, old);

              3)設置具備動畫效果的DOM元素的position屬性爲fixed或absolute

                   把頁面中具備動畫效果的DOM元素設置爲絕對定位,使得元素脫離頁面佈局流,從而避免了頁面的重排,只涉及動畫元素自身的重排了。

              4)謹慎取得DOM元素的佈局信息

                   獲取DOM元素的佈局信息會有性能的損耗,若是存在重複調用。最佳的作法是儘可能把這些值緩存在局部變量中。

 for (var i=0; i<len; i++) { myElement[i].style.top = targetElement.offsetTop + i*5 +'px'; }
 //優化方案
        var targetTop = targetElement.offsetTop; for (var i=0; i<len; i++) { myElement[i].style.top = targetTop + i*5 +'px'; }

                       另外,由於取得DOM元素的佈局信息會強制瀏覽器刷新渲染樹,而且可能會致使頁面的重繪或重排,因此在有大批量DOM操做時,應避免獲取DOM元素的佈局信息,使得瀏覽器針對大批量DOM操做的優化不被破壞。若是須要這些佈局信息,最好在DOM操做以前就取得。

 var newWidth = div1.offsetWidth + 10; div1.style.width = newWidth + 'px'; var newHeight = div1.offsetHeight + 10;  //強制頁面重排
        div1.style.height = newHeight + 'px';    //又會重排一次
 //優化方案
 var newWidth = div1.offsetWidth + 10; var newHeight = div1.offsetHeight + 10; div1.style.width = newWidth + 'px'; div1.style.height = newHeight + 'px';

                5)使用事件託管方式綁定事件

                      在DOM事件上綁定事件會影響頁面的性能,一方面,綁定事件自己會佔用處理時間,另外一方面,瀏覽器保存事件綁定,綁定事件也會佔用內存。在頁面中綁定的事件越少越好。一個優雅的手段是使用事件託管方式,即利用事件冒泡機制,只在父元素上綁定事件處理,用於處理全部子元素的事件,在事件處理函數中根據傳入的參數判斷事件源元素,針對不一樣的源元素作不一樣的處理。

五、使用輔助工具優化JavaScript代碼性能

      性能優化必定要有目標和尺度,而不是靠感受。

      在作JavaScript代碼性能優化時,首先是查看JavaScript代碼文件的加載狀況。可使用各瀏覽器自帶的開發工具。

      不少性能檢查工具也會檢查代碼文件的加載狀況,並給出有價值的建議,如壓縮代碼、合併代碼、調整代碼加載順序、延遲加載代碼等。這類工具備PageSpeed、YSlow等。這類工具會從頁面總體進行檢查,而不是僅僅檢查JavaScript代碼文件。

      高性能的Web網頁,要求網頁渲染過程當中達到理想的60幀/秒的幀率。

相關文章
相關標籤/搜索