【讀書筆記】讀《高性能JavaScript》

  這本《高性能JavaScript》講述了有關JavaScript性能優化的方方面面,主要圍繞如下幾個方面:javascript

1> 加載順序
2> 數據訪問(如怎樣的數據類型訪問最快,怎樣的做用域鏈最優)
3> DOM編程(如怎樣的方式訪問DOM元素性能是最優的)
4> 字符串和正則 
5> Ajax
6> 編程實踐(性能測試工具的使用、建立與部署JavaScript應用程序、如何提高程序響應)
var script = document.createElement ("script");
script.type = "text/javascript";
script.src = "file1.js";
document.getElementsByTagName_r("head")[0].appendChild(script);
  新的<script>元素加載file1.js源文件。此文件當元素添加到頁面以後馬上開始下載。此技術的重點在於:不管在何處啓動下載,文件的下載和運行都不會阻塞其餘頁面處理過程。你甚至能夠將這些代碼放在<head>部分而不會對其他部分的頁面代碼形成影響(除了用於下載文件的HTTP鏈接)。用XHR對象下載代碼,並注入到頁面中。(能夠下載不當即執行的JavaScript代碼)
var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
            var script = document.createElement_x("script");
            script.type = "text/javascript";
            script.text = xhr.responseText;
            document.body.appendChild(script);
        }
    }
};
xhr.send(null);

  ——推薦的非阻塞模式html

推薦的向頁面加載大量JavaScript的方法分爲兩個步驟:
  第一步,包含動態加載JavaScript所需的代碼,而後加載頁面初始化所需的除JavaScript以外的部分。這部分代碼儘可能小,可能只包含loadScript()函數,它下載和運行很是迅速,不會對頁面形成很大幹擾。當初始代碼準備好以後,用它來加載其他的JavaScript。
function loadScript(url, callback) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    //IE
    if (script.readyState) {
        script.onreadystatechange = function() {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        }
    } else {
        //非IE
        script.onload = function() {
            callback();
        }
    }
    script.src = url;
    document.getElementById("head").appendChild(script);
}
  第二步,應用loadScript函數在body的關閉標籤以前的位置加載其他須要加載的JavaScript代碼。

  第二章:數據訪問前端

  在JavaScript中,數據存儲位置能夠對代碼總體性能產生重要影響。有四種數據訪問類型:直接量(字符串、數字、布爾值、對象、數組、函數、正則、null、undefined),變量(var局部變量),數組項(array[index]),對象成員(obj.propName | obj[‘propName’])。它們有不一樣的性能考慮。java

  直接量和局部變量訪問速度很是快,數組項和對象成員須要更長時間。正則表達式

  局部變量比域外變量快,由於它位於做用域鏈的第一個對象中。變量在做用域鏈中的位置越深,訪問所需的時間就越長。全局變量老是最慢的,由於它們老是位於做用域鏈的最後一環。算法

  避免使用with表達式,由於它改變了運行期上下文的做用域鏈。並且應當當心對待try-catch表達式的catch子句,由於它具備一樣效果。編程

應用with包含的變量對象被插入到做用域鏈的前端,正因如此,訪問激活對象被擠到了第二層,會致使訪問局部變量的性能降低。故應避免。

  嵌套對象成員會形成重大性能影響,儘可能少用。跨域

因爲對象成員可能包含其它成員,例如不太常見的寫法window.location.href這種模式。每遇到一個點號,JavaScript引擎就要在對象成員上執行一次解析過程。成員嵌套越深,訪問速度越慢。
通常來講,若是在同一個函數中你要屢次讀取同一個對象屬性,最好將它存入一個局部變量。以局部變量替代屬性,避免多餘的屬性查找帶來性能開銷。在處理嵌套對象成員時這點特別重要,它們會對運行速度產生難以置信的影響。

  一個屬性或方法在原形鏈中的位置越深,訪問它的速度就越慢。數組

  通常來講,你能夠經過這種方法提升JavaScript代碼的性能:將常用的對象成員,數組項,和域外變量存入局部變量中。而後,訪問局部變量的速度會快於那些原始變量。瀏覽器

  第三章:DOM編程

  DOM訪問和操做是現代網頁應用中很重要的一部分。但每次你經過橋樑從ECMAScript島到達DOM島時,都會被收取「過橋費」。爲減小DOM編程中的性能損失,請牢記如下幾點:

  最小化DOM訪問,在JavaScript端作儘量多的事情。

  在反覆訪問的地方使用局部變量存放DOM引用。

 對於任何類型的DOM訪問,若是同一個DOM屬性或方法被訪問一次以上,最好使用一個局部變量緩存該DOM成員。

  當心地處理HTML集合,由於他們表現出「存在性」,老是對底層文檔從新查詢。將集合的length屬性緩存到一個變量中,在迭代中使用這個變量。若是常常操做這個集合,能夠將集合拷貝到數組中。

當遍歷一個集合時,第一個優化是將集合引用存儲於局部變量,並在循環以外緩存length屬性,而後, 若是在循環體中屢次訪問同一個集合元素,那麼使用局部變量緩存它。

  注意重繪和重排版;批量修改風格,離線操做DOM樹,緩存並減小對佈局信息的訪問。動畫中使用絕對座標。

1.重排版的狀況列舉:
    1>添加或刪除可見的DOM元素
    2>元素位置改版
    3>元素尺寸改變(外邊距、邊框寬度、內邊距、寬度、高度)
    4>內容改變(如,文本改變或圖片被另外一個不一樣尺寸的所替代)
    5>瀏覽器窗口改變尺寸(如出現滾動條)
  2.重排版和重繪代價昂貴,因此,提升程序響應速度一個好策略是減小此類操做發生的機會。3.爲減小發生次數,你應該將多個DOM和風格改變合併到一個批次中一次性執行。
    1>當須要對DOM元素進行屢次修改時,你能夠經過如下步驟減小重繪和重排版的次數
      從文檔流中摘除該元素
      (1)隱藏元素,進行修改,而後再顯示它。
      (2)使用一個文檔片斷在已存DOM以外建立一個子樹,而後將它拷貝到文檔中。
      (3)將原始元素拷貝到一個脫離文檔的節點中,修改副本,而後覆蓋原始元素。
    2>對其應用多重改變
    3>將元素帶回文檔中
  4.對於處理具備動畫效果的元素,須要將之脫離文檔流

  使用事件託管技術最小化事件句柄數量。

  第四章:算法和流程控制

  正如其餘編程語言,代碼的寫法和算法選用影響JavaScript的運行時間。與其餘編程語言不一樣的是,JavaScript可用資源有限,因此優化技術更爲重要。

 瀏覽器資源限制:
    1>調用棧尺寸限制
    2>長時間腳本限制(控制在100ms之內的響應算做好的用戶體驗)

  for,while,do-while循環的性能特性類似,誰也不比誰更快或更慢。

  除非你要迭代遍歷一個屬性未知的對象,不然不要使用for-in循環。

  改善循環性能的最好辦法是減小每次迭代中的運算量,並減小循環迭代次數。

  運行的代碼總量越大,使用這些策略所帶來的性能提高就越明顯。

  第五章:字符串和正則表達式

  密集的字符串操做和粗淺地編寫正則表達式多是主要性能障礙,但本章中的建議可幫助您避免常見缺陷。

  當鏈接數量巨大或尺寸巨大的字符串時,數組聯合是IE7和它的早期版本上惟一具備合理性能的方法。

  若是你不關心IE7和它的早期版本,數組聯合是鏈接字符串最慢的方法之一。使用簡單的+和+=取而代之,可避免(產生)沒必要要的中間字符串。

  提升正則表達式效率的各類技術手段,幫助正則表達式更快地找到匹配,以及在非匹配位置上花費更少時間。

  正則表達式並不老是完成工做的最佳工具,尤爲當你只是搜索一個文本字符串時。

雖然有不少方法來修整一個字符串,使用兩個簡單的正則表達式(一個用於去除頭部空格,另外一個用於去除尾部空格)提供了一個簡潔、跨瀏覽器的方法,適用於不一樣內容和長度的字符串。從字符串末尾開始循環查找第一個非空格字符,或者在一個混合應用中將此技術與正則表達式結合起來,提供了一個很好的替代方案,它不多受到字符串總體長度的影響。

  第六章:響應接口

  JavaScript和用戶界面更新在同一個進程內運行,同一時刻只有其中一個能夠運行。這意味着當JavaScript代碼正在運行時,用戶界面不能響應輸入,反之亦然。有效地管理UI線程就是要確保JavaScript不能運行太長時間,以避免影響用戶體驗。最後,請牢記以下幾點:

  JavaScript運行時間不該該超過100毫秒。過長的運行時間致使UI更新出現可察覺的延遲,從而對總體用戶體驗產生負面影響。

  JavaScript運行期間,瀏覽器響應用戶交互的行爲存在差別。不管如何,JavaScript長時間運行將致使用戶體驗混亂和脫節。

  定時器可用於安排代碼推遲執行,它使得你能夠將長運行腳本分解成一系列較小的任務。

  網頁工人線程是新式瀏覽器才支持的特性,它容許你在UI線程以外運行JavaScript代碼而避免鎖定UI。

  網頁應用程序越複雜,積極主動地管理UI線程就越顯得重要。沒有什麼JavaScript代碼能夠重要到容許影響用戶體驗的程度。

  第七章:Ajax

  高性能Ajax包括:知道你項目的具體需求,選擇正確的數據格式和與之相配的傳輸技術。

  做爲數據格式,純文本和HTML是高度限制的,但它們可節省客戶端的CPU週期。XML被普遍應用廣泛支持,但它很是冗長且解析緩慢。JSON是輕量級的,解析迅速(做爲本地代碼而不是字符串),交互性與XML至關。字符分隔的自定義格式很是輕量,在大量數據集解析時速度最快,但須要編寫額外的程序在服務器端構造格式,並在客戶端解析。

  當從頁面域請求數據時,XHR提供最完善的控制和靈活性,儘管它將全部傳入數據視爲一個字符串,這有可能下降解析速度。另外一方面,動態腳本標籤插入技術容許跨域請求和本地運行JavaScript和JSON,雖然它的接口不夠安全,並且不能讀取信息頭或響應報文代碼。多部分XHR可減小請求的數量,可在一次響應中處理不一樣的文件類型,儘管它不能緩存收到的響應報文。當發送數據時,圖像燈標是最簡單和最有效的方法。XHR也可用POST方法發送大量數據。

  減小請求數量,可經過JavaScript和CSS文件打包,或者使用MXHR。

  縮短頁面的加載時間,在頁面其它內容加載以後,使用Ajax獲取少許重要文件。

  Ajax是提高你網站潛在性能之最大的改進區域之一,由於不少網站大量使用異步請求,又由於它提供了許多不相關問題的解決方案,這些問題諸如,須要加載太多資源。對XHR的創造性應用是如此的不同凡響,它不是呆滯不友好的界面,而是響應迅速且高效的代名詞;它不會引發用戶的憎恨,誰見了它都會愛上它。

  第八章:編程實踐

  JavaScript提出了一些獨特的性能挑戰,關係到你組織代碼的方法。網頁應用變得愈來愈高級,包含的JavaScript代碼愈來愈多,出現了一些模式和反模式。請牢記如下編程經驗:

  經過避免使用eval_r()和Function()構造器避免二次評估。此外,給setTimeout()和setInterval()傳遞函數參數而不是字符串參數。

  建立新對象和數組時使用對象直接量和數組直接量。它們比非直接量形式建立和初始化更快。

  避免重複進行相同工做。當須要檢測瀏覽器時,使用延遲加載或條件預加載。

//之前的方法
function addHandler(target, eventType, handler) {
    if (target.addEventListener) {//DOM2 Events
        target.addEventListener(eventType, handler, false);
    } else {//IE
        target.attachEvent("on" + eventType, handler);
    }
}
function removeHandler(target, eventType, handler) {
    if (target.removeEventListener) {//DOM2 Events
        target.removeEventListener(eventType, handler, false);
    } else {//IE
        target.detachEvent("on" + eventType, handler);
    }
}
//延遲加載
function addHandler(target, eventType, handler){
    debugger;
    //overwrite the existing function
    if (target.addEventListener){ //DOM2 Events
        addHandler = function(target, eventType, handler){
            target.addEventListener(eventType, handler, false);
        };
    } else { //IE
        addHandler = function(target, eventType, handler){
            target.attachEvent("on" + eventType, handler);
        };
    }
    //call the new function
    addHandler(target, eventType, handler);
}
function removeHandler(target, eventType, handler){
    //overwrite the existing function
    if (target.removeEventListener){ //DOM2 Events
        removeHandler = function(target, eventType, handler) {
            target.addEventListener(eventType, handler, false);
        }
    } else { //IE
        removeHandler = function(target, eventType, handler) {
            target.detachEvent("on" + eventType, handler);
        };
    }
    //call the new function        
    removeHandler(target, eventType, handler);
}
//條件預加載
var addHandler = document.body.addEventListener ? function(target, eventType, handler) {
    target.addEventListener(eventType, handler, false);
} : function(target, eventType, handler) {
    target.attachEvent("on" + eventType, handler);
};
var removeHandler = document.body.removeEventListener ? function(target, eventType, handler) {
    target.removeEventListener(eventType, handler, false);
} : function(target, eventType, handler) {
    target.detachEvent("on" + eventType, handler);
};

  當執行數學運算時,考慮使用位操做,它直接在數字底層進行操做,性能最優。

  原生方法老是比JavaScript寫的東西要快。儘可能使用原生方法。

  本書涵蓋了不少技術和方法,若是將這些優化應用在那些常常運行的代碼上,你將會看到巨大的性能提高。

  第九章:建立並部署高性能JavaScript應用程序

  開發和部署過程對基於JavaScript的應用程序能夠產生巨大影響,最重要的幾個步驟以下:

  合併JavaScript文件,減小HTTP請求的數量。

  使用YUI壓縮器緊湊處理JavaScript文件。

  以壓縮形式提供JavaScript文件(gzip編碼)。

  經過設置HTTP響應報文頭使JavaScript文件可緩存,經過向文件名附加時間戳解決緩存問題。

  使用內容傳遞網絡(CDN)提供JavaScript文件,CDN不只能夠提升性能,它還能夠爲你管理壓縮和緩存。

  全部這些步驟應當自動完成,不管是使用公開的開發工具諸如Apache Ant,仍是使用自定義的開發工具以實現特定需求。若是你使這些開發工具爲你服務,你能夠極大改善那些大量使用JavaScript代碼的網頁應用或網站的性能。

  第十章:工具

  當網頁或應用程序變慢時,分析網上傳來的資源,分析腳本的運行性能,使你可以集中精力在那些須要努力優化的地方。

  使用網絡分析器找出加載腳本和其它頁面資源的瓶頸所在,這有助於決定哪些腳本須要延遲加載,或者進行進一步分析。

  傳統的智慧告訴咱們應儘可能減小HTTP請求的數量,儘可能延遲加載腳本以使頁面渲染速度更快,向用戶提供更好的總體體驗。

  使用性能分析器找出腳本運行時速度慢的部分,檢查每一個函數所花費的時間,以及函數被調用的次數,經過調用棧自身提供的一些線索來找出哪些地方應當努力優化。

  雖然花費時間和調用次數一般是數據中最有價值的點,仍是應當仔細察看函數的調用過程,可能發現其它優化方法。

  這些工具在那些現代代碼所要運行的編程環境中再也不神祕。在開始優化工做以前使用它們,確保開發時間用在解決問題的刀刃上。

 

  傳個logo做記念——

  

  原文英文及翻譯:《高性能JavaScript》

相關文章
相關標籤/搜索