跳到主要內容
黯羽輕揚每天積累一點點

JS 學習筆記 12_優化

免費2015-04-14#JS#js性能优化

本文包括可維護性優化,性能優化和發布優化

一。可維護性優化

###1. 添加註釋

註釋能夠增強代碼的可讀性以及可維護性,當然,理想情況是滿滿的註釋,但這不太現實。所以我們只需要在一些關鍵的地方添上註釋:

  • 函數和方法:尤其是返回值,因為直接看不出來

  • 大段代碼(功能模組):說明模組功能

  • 複雜算法:寫出關鍵點,方便理解

  • Hack:說明為了修復什麼問題,當前方案是否完善,能否改進

###2.「暗示」變量類型

通過初始值來暗示,例如:

var found = false;
var count = 1;
var name = '';
var student = null;

###3. 解耦(分層)

  • 結構層:HTML

  • 行為層:JS

  • 表現層:CSS

盡量不要「越權」,如果實在是想越權,也應該用文檔或者註釋說明。盡量不要出現緊耦合,例如:

  • JS-HTML:

     elem.innerHTML = '<div class="block"><h2>title</h2><p>content</p></div>';
     //最好用下面的方式代替(顯示頁面中的隱藏元素)
     //elem.style.display = 'block';
    
  • JS-CSS:

     elem.style.color = '#e0e0e0';
     //最好用下面的方式代替(設置類,不要直接設置樣式)
     //elem.className = 'my_class';
    
  • JS-JS:

     //邏輯耦合
     elem.onclick = function(e){
       if(txt.value !== null && txt.value !== '' &&...){
         //DOM 操作
       }
     }
     //最好用下面的方式代替(分離邏輯功能塊)
     function isValid(){
       return txt.value !== null && txt.value !== '' &&...;
     }
     function display(){
       //DOM 操作
     }
     elem.onclick = function(e){
       if(isValid()){
         display();
       }
     }
    

避免邏輯耦合的幾條原則:

  • 不要傳遞 event 對象,只傳需要的數據

  • 觸發事件不應該是執行動作的唯一方式

  • 事件處理器應該只處理事件相關數據(獲取事件源,坐標值等等),然後把處理轉交給應用邏輯

###4. 編碼原則

  • 尊重對象所有權,不要隨便修改別人的對象,具體要求:

    • 不要給實例/原型添加屬性或方法

    • 不要重寫已存在的方法

可選方案:

-  組合:創建實現了所需功能的新對象,引用需要的對象

-  繼承:創建自定義類型,繼承需要修改的類型,然後添加額外功能
  • 用命名空間避免全域變量,例如:

     var mySystem = {};
     mySystem.mod1 = {...};
    
  • 用常量提高可維護性,例如:

     var Consts = {};
     Consts.IMG_PATH = '../imgs/';
     
    

注意:常量包括常用的 CSS 類名和其它任何可能影響維護的值

二。性能優化

###1. 避免長作用域鏈查找

把需要多次引用的全域變量另存為局部變量

###2. 盡量不要用 with 語句

with 語句會延長作用域,存在長作用域查找的開銷,可以用另存局部變量來代替(沒有 with 方便,但多少能好一點)

###3. 避免不必要的屬性查找

  1. 盡量把重複使用的值另存為局部變量,例如:

    //不要用下面的代碼(6 次屬性查找)
    var qs = window.location.href.substring(window.location.href.indexOf('?'));
    //應該用下面的代碼(4 次,而且更具可讀性)
    var url = window.location.href;
    var qs = url.substring(url.indexOf('?'));
    
  2. 優化循環

    • 減值迭代更快(i--)

    • 簡化終止條件,每次循環都會檢查終止條件,簡化條件能提高效率

    • 簡化循環體,盡量減少循環體裡面的計算量

    • 使用後測試循環(do...while),可以避免第一次循環前的判斷

  3. 展開循環

如果循環次數確定,最好不要用循環,因為循環存在創建循環和處理終止條件的額外開銷,例如:

    for(i = 0;i < 2;i++){
      process(arr[i]);
    }
    //下面的比上面的快
    process(arr[0]);
    process(arr[1]);
    process(arr[2]);
    

如果循環次數不能確定,可以用 Duff 技術(Tom Duff 發明的)展開一部分循環,提高效率,例如:

    //credit: Jeff Greenberg for JS implementation of Duff's Device
    //假設 values.length > 0
    var iterations = Math.ceil(values.length / 8);
    var startAt = values.length % 8;
    var i = 0;
    do {
        switch(startAt){
            case 0: process(values[i++]);
            case 7: process(values[i++]);
            case 6: process(values[i++]);
            case 5: process(values[i++]);
            case 4: process(values[i++]);
            case 3: process(values[i++]);
            case 2: process(values[i++]);
            case 1: process(values[i++]);
        }
        startAt = 0;
    } while (--iterations > 0);
    //以上代碼來自:http://www.cnblogs.com/kylindai/archive/2013/12/04/3458476.html

或者另一個更快的 Duff 方法:

    //credit: Speed Up Your Site (New Riders, 2003)
    var iterations = Math.floor(values.length / 8);
    var leftover = values.length % 8;
    var i = 0;
    if (leftover > 0){
        do {
            process(values[i++]);
        } while (--leftover > 0);
    }
    do {
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
        process(values[i++]);
    } while (--iterations > 0);
    //以上代碼來自:http://www.cnblogs.com/kylindai/archive/2013/12/04/3458476.html

4. 避免雙重解釋

雙重解釋是指:用 js 解析 js。具體是用 eval() 函數或者 new Function(strCode) 或者 setTimeout(strCode)

雙重解釋的缺點:需要再啟動一個解析器來解析,存在很大的開銷,比直接解析慢很多

  1. 原生方法更快

原生方法是用用 C/C++ 編譯好的模組,所以要快得多

  1. switch 比 if-else 快

原因不好說,可以參考 CSDN

  1. 位運算並沒有更快

在其它語言中把數學運算簡化為位運算能夠提升計算速度,但js 中沒這一說,因為 js 內部只有一種數值類型(double),所以做位運算需要折騰:double - int - 做位運算 - double,性能可想而知

  1. 減少語句數量

    • 用 1 個 var 聲明多個變量

    • 插入迭代值,arr[i++] 一條語句搞定,不用把 i++ 獨立成一個語句

    • 用數組/對象字面量,代碼行數明顯變少了

  2. DOM 優化

    • 減少現場更新,可以用 DocumentFragment 優化

    • 用 innerHTML 創建 DOM 節點比創建一堆節點再組裝要快,但存在 JS-HTML 耦合問題,慎重考慮

    • 用事件委託

    • 注意實時更新的集合(NodeList、NamedNodeMap、HTMLCollection)

    除了把引用另存為局部變量外,還要注意訪問其屬性也是需要重新查詢的,比如:var imgs = document.images; 訪問 imgs.length 也需要再查一次

三。發布優化

  1. 用驗證工具(如 JSLint)檢查代碼,發現語法錯誤之外的潛在問題

  2. 去掉註釋(出於安全性考慮)

  3. 合併 js 文件,盡量減少外部文件數量

  4. 壓縮代碼(如 YUI 壓縮器),減少代碼本身大小,也可以同時混淆代碼,提高安全性,但混淆代碼本身存在風險,可能引發錯誤

  5. 開啟服務器壓縮功能,例如 gzip 模組

評論

暫無評論,快來發表你的看法吧

提交評論