JavaScript 性能提高之路

  在平時工做作項目的過程當中咱們有時候會遇到頁面加載好久才加載出來的狀況,這樣嚴重影響了用戶的體驗效果。雖說有時候多是由於網絡問題,但有些時候確實是前端代碼沒有足夠優化致使的。因此經過查閱相關資料並實踐後,總結出以下知識點來提高性能。有什麼寫得不對的地方還但願各路大神指出並加以指點。javascript

一、數據訪問

一、將全部script標籤放在儘量接近body標籤底部的位置,儘量減小對整個頁面下載的影響。css

二、儘可能少用全局變量(解決辦法:使用嚴格模式能夠避免)。由於變量在做用域鏈中的位置越深,訪問的時間就越長。局部變量位於做用域鏈中的第一個對象中,全局變量老是位於做用域鏈的最後一環,因此全局變量老是最慢的。
三、避免全局查詢,若是必定要用到全局變量時,而且須要在某個函數中屢次用到該全局變量時,能夠定義一個局部變量指向全局變量,來縮短在做用域鏈中的查詢深度。html

function addTotrackData(){
    	var allChildrenNode=getAllChildrenDepartmentNodes();
    	for (var i = 0; i < allChildrenNode.length; i++) {
            for (var j=0,len=track.length;j<len;j++) {
                if (trackNode[j]["userId"] == allChildrenNode[i]) {
                    trackNode[j]["isOnMap"] = true;
                }
            }
        }
    }
複製代碼

上面代碼能夠改寫爲以下所示前端

function addTotrackData(){
    	var allChildrenNode=getAllChildrenDepartmentNodes();
    	var track=trackNode;
    	for (var i = 0; i < allChildrenNode.length; i++) {
            for (var j=0,len=track.length;j<len;j++)  {
                if (track[j]["userId"] == allChildrenNode[i]) {
                    track[j]["isOnMap"] = true;
                }
            }
        }
    }
複製代碼

四、將集合的length屬性用一個局部變量來保存,在迭代中使用該變量。java

for (var j=0,len=track.length;j<len;j++) 
複製代碼

四、避免使用with表達式,由於它增長做用域鏈的長度(with能夠將一個沒有或有多個屬性的對象處理一個徹底隔離的詞法做用域,同時定義在這個with塊內部var聲明會被添加早with所在的函數做用域中),with一般被當作重複引用同一個對象的多個屬性的快捷方式,能夠不須要重複引用對象自己。並且應當當心的對待try-catch的catch子句,它具備一樣效果。 //例子1 var obj={ a:1, b:2, c:3 } //簡單的快捷方式 with(obj){ a=2; b=3; c=4 }ajax

//例子2
    function foo(obj){
        with(obj){
            a=2;
        }
    }
    var obj1={
        a:1
    }
    var obj2={
        b:3
    }
    foo(obj1);
    console.log(obj1.a);//2
    foo(obj2);
    console.log(obj.a);//undefined
    console.log(a);//2  a被泄露到全局做用域上,with中只會對傳入的對象屬性進行修改,不能給對象添加新屬性。
複製代碼

五、一個屬性或方法在原型鏈中的位置越深,它的訪問速度就越慢。
六、聲明變量時,多個變量合併聲明,能夠減小內存消耗。數組

var a;
    var b;
    var c;
    //推薦
    var a,b,c
複製代碼

七、不要使用eval(功能是把對應的字符串解析成JS代碼並運行),不安全,很是耗性能(2次,一次解析成js語句,一次執行),同時也會對eval()所在的詞法做用域進行修改。瀏覽器

function foo(str,a){
        aval(str);//改變詞法做用域
        console.log(a,b)
    }
    var b=2;
    foo("var b=3",1);
複製代碼

八、利用圖像燈標實現向服務器快速傳送數據。格式:(new Image).src=url?params.join("&")。
九、用數組和對象的直接量建立對象和數組,比非直接量形式建立和初始化更快。緩存

var obj={};
    var arr=[];
複製代碼

十、儘可能使用javascript自帶的原生方法,如Math.abs()。
十一、避免重複進行相同操做。如須要檢測瀏覽器時,使用延遲加載和條件預加載(?三元符) 延遲加載的代碼以下:安全

function addhandler(target,eventType,handler){
    	if(target.addEventListener){
    		addhandler=function(){
    			target.addEventListener(eventType,handler,false);
    		};
    	}else{
    		addhandler=function(){	
    		    target.addEventListener("on"+eventType,handler)
    		};
    	}
    	addhandler(target,eventType,handler);
    }
    var dom=document.getElementById("test");
    addhandler(dom,"click",function(){
    	console.log("測試");
    })   
複製代碼

十二、減小ajax的請求次數。 在服務器端,設置http頭,確保返回報文被緩存在瀏覽器端(Expires頭告訴瀏覽器應當緩存返回報文多長時間,其值是一個日期。超過這個日期發起請求後,都將從服務器獲取數據。同時向文件名附加時間戳能夠解決緩存問題。

格式:Expires: Mon, 28 Jul 2014 23:30:00 GM)。
複製代碼

1三、使用內容傳遞網絡(CDN——經過地理位置上最近的位置向用戶提供服務,減小網絡延遲)提供javascript文件,在提升性能的同時,還能夠管理壓縮和緩存。

二、Dom操做

  Dom(文檔對象模型)是一個獨立於語言的,使用xml和html文檔操做的應用程序接口。在瀏覽器中的接口倒是以javascript來實現的。Dom和javascript當作兩座島,二者之間經過一座收費的橋鏈接。通常建議儘可能留在javascript島上。

一、用innerHTML代替DOM操做,減小DOM操做次數,優化javascript性能。

//dom方式
    var str=""
    var dom=document.getElementById("test");
    var start1=new Date();
    for(var j=0;j<100000;j++){
    	var div=document.createElement("div");
    	div.innerText="test";
    	dom.append(div);					
    }
    var end1=new Date();
    console.log("dom方式:"+(end1-start1));//dom方式:356
    
    //inerHTML方式
    var content="";
    var start=new Date();
    for(var i=0;i<10000;i++){
        content=content+"<div>test</div>";
    }
    document.getElementById("test").innerHTML=content;
    var end=new Date();
    console.log("innerHTML方式:"+(end-start));//innerHTML方式:35
複製代碼

二、 若是統一個Dom元素或集合被訪問一次以上,最好使用一個局部變量來緩存此Dom成員,在循環中使用局部變量緩存集合引用和集合元素會提高速度。
三、遍歷children比childNodes更快。children不區分(包括)註釋節點和空文本節點,因此快一些。
四、使用element.cloneNode(bool)複製節點,bool爲false表示淺複製,只複製當前節點,bool爲true時,表示深複製,還會複製其子節點。這種方式比document.createElement()速度要快一些。
五、 使用document.querySelector和document.querySelectorAll("div.warning,div.notice")來快速查找。由於它們返回一個NodeList——由符合條件的節點構成的類數組對象,而不是HTML集合(老是表現出存在性),避免了它所固有的性能問題(以及存在的邏輯問題)。querySelectorAll("div.warning,div.notice")還能夠進行聯合查詢。
六、修改樣式時,可使用div.style.cssText來一塊兒修改樣式,或者使用類來修改(便於維護)。

var el = document.getElementById('mydiv');
     //修改3次Dom
    el.style.borderLeft = '1px';
    el.style.borderRight = '2px';
    el.style.padding = '5px';
    //推薦只須要修改1次Dom
    el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;'  
複製代碼

七、儘可能避免寫在HTML標籤中寫Style屬性,使用外聯樣式便於維護和修改。
八、避免圖片和iFrame等的空Src。空Src會從新加載當前頁面,影響速度和效率。
九、採用事件委託。元素鏈接事件句柄會影響頁面性能,採用委託利用事件冒泡的性能減小元素鏈接事件。(事件掛接過程都是發生在onload或DOMContentReady)事件中。
十、避免使用css表達式,避免使用高級選擇器(如後代、僞類選擇器),通配選擇器。
十一、壓縮文件(gzip),能夠減小內存佔用,同時減小查詢時間。
十二、合併樣式和腳本、使用css圖片精靈(雪碧圖)(這樣作是爲了減小向服務器的請求數量,從而達到性能優化的效果)。
1三、縮短頁面的加載時間,先將頁面結構顯示出來,而後使用ajax獲取剩下的重要文件。

三、循環

一、for-in是四種循環方法中速度最慢的一種,通常用於循環對象(須要查找自身屬性仍是原型屬性)。不建議循環數組。除非要迭代遍歷一個屬性未知的對象,不然通常不用for-in。
二、改變循環條件的順序來提升循環性能。

//推薦
    for(var i=items.length;i--;){
        //todo
    }
    //不推薦
    for(var i=0,len=items.length;i<len;i++){
        //todo
    }   
複製代碼

三、經過減小循環體來優化性能。