用測試工具JSLitmus來告訴你幾個提高JavaScript性能的小技巧

性能測試工具

JSLitmusjavascript

dom操做

測試代碼

<div id="domTestWrap">
    <div class="dom-test-content">
        <span class="dom-test-text"></span>
    </div>
    <div class="dom-test-content">
        <span class="dom-test-text"></span>
    </div>
    <div class="dom-test-content">
        <span class="dom-test-text"></span>
    </div>
</div>
function domTestDepthOne () {
    document.getElementById('domTestWrap')
}
function domTestDepthOneQS () {
    document.querySelector('#domTestWrap')
}
function domTestDepthTwo () {
    document.getElementById('domTestWrap').getElementsByClassName('dom-test-content')
}
function domTestDepthTwoQSA () {
    document.querySelectorAll('#domTestWrap .dom-test-content')
}
function domTestDepthThree () {
    var domTestTextList = document.getElementById('domTestWrap').getElementsByClassName('dom-test-content')
    for (var i=0; i< domTestTextList.length; i++) {
        domTestTextList[i].innerHTML
    }
}
function domTestDepthThreeQSA () {
    var domTestTextList = document.querySelectorAll('#domTestWrap .dom-test-content')
    for (var i=0; i< domTestTextList.length; i++) {
        domTestTextList[i].innerHTML
    }
}
JSLitmus.test('dom test depth one', domTestDepthOne)
JSLitmus.test('dom test depth one query selecter', domTestDepthOneQS)
JSLitmus.test('dom test depth two', domTestDepthTwo)
JSLitmus.test('dom test depth two query selecter all', domTestDepthTwoQSA)
JSLitmus.test('dom test depth three query', domTestDepthThree)
JSLitmus.test('dom test depth three query selecter all', domTestDepthThreeQSA)

測試結果

dom操做-測試結果

PS:黃條表明每秒可執行測試函數的次數,固然越多越快。java

分析總結

dom操做很是耗時,querySelector&querySelectorAll書寫方便但相比web

document.getElementById更加耗時些。務必減小dom操做,減小無心義的dom路徑的查找。正則表達式

對象操做

測試代碼

var objectTest = {
    one : {
        name: 'one',
        value: 1,
        two: {
            name: 'two',
            value: 2,
            three: {
                name: 'three',
                value: 3
            }
        }
    }
}

var three = objectTest.one.two.three;
function objectTestDepthZero () {
    three.name
    three.value
}

function objectTestDepthThree () {
    objectTest.one.two.three.name
    objectTest.one.two.three.value
}


JSLitmus.test('object test depth zero', function (count) {
    while (count -- ) objectTestDepthZero()
})
JSLitmus.test('object test depth three', function (count) {
    while (count -- ) objectTestDepthThree()
})

測試結果

對象操做-測試結果

分析總結

對象屬性的訪問很是耗時,緣由於JavaScript引擎內部存儲變量的結構有關,JavaScript是弱類型語言,它不像強類型語言如C、C++那樣能夠經過內存地址偏移來快速訪問。segmentfault

能夠參考,用最簡單易懂的道理告訴你,爲何JavaScript在現代引擎(V8,JavaScriptCore)下,能表現出卓越性能!數組

務必減小對象嵌套的深度,減小無心義的對象路徑的查找緩存

做用域冒泡

測試代碼

測試代碼來自JSLitmus官網主頁的例子性能優化

// 不少開發者不知道變量做用域對於腳本的性能有多少影響。
// 爲了直觀地展現這一點,咱們寫了下面的JSLitmus測試用例去測量對定義在不一樣做用域下的變量
// 執行"遞增(++)"操做的表現

// 首先,測試定義在全局做用域的變量
var global_var = 1;
JSLitmus.test('global', function(count) {
  while (count--) global_var++;}
);

// 如今測試一個定義在局部函數做用域的變量
JSLitmus.test('local', function(count) {
  var local_var = 1;
  while (count--) local_var++;
});

// 嘗試測試一個綁定到當即執行函數內的變量。
// 喜歡Prototype和JQuery的開發者應該以爲這樣特別有意思
JSLitmus.test('closure',
  (function() {
    var closure_var = 1;
    return function(count) {while (count--) closure_var++;}
  })()
);

// 仍是綁定在當即執行函數中的變量,不過此次套了兩層
JSLitmus.test('multi-closure',
  (function() {
    var multi_var = 1;
    return (function() {
      return function(count) {while (count--) multi_var++;}
    })()
  })()
);

// 測試一個空的函數調用,這能夠做爲一個參照點
JSLitmus.test('empty function call', function(count) {
  var f = function() {};
  while (count--) f();
});

測試結果

做用域冒泡-測試結果

分析總結

每次訪問變量或者函數都會進行一次做用域冒泡的過程,因此本地做用域如函數做用域是最快的,全局做用域最慢。
應該要儘可能減小這個冒泡的層數,對於要常常訪問的全局變量,應該在本地做用域作一個緩存。dom

其餘測試

測試代碼

這些測試代碼來自,JSLitmus官網的例子函數

// 這是一個空的非循環測試。它的結果應該是一秒能夠作無限次,或者很是接近無限的一個值
JSLitmus.test('empty test (non-looping)', function() {});

// 這是一個空的循環測試,對於這種執行很是快的代碼,須要執行更屢次才能獲得比較準確的結果
// 因此常常使用循環測試
// 它的結果應該是一秒能夠作無限次,或者很是接近無限的一個值
JSLitmus.test('empty test', function(count) {
  while (count--);
});

// 測試調用一個定義在全局做用域的函數的消耗
var emptyFunction = function() {};
JSLitmus.test('function overhead (non-looping)', function() {
  emptyFunction();
});

// 循環測試調用一個定義在本地做用域函數的消耗。
// 這個應該比前者更快,一個緣由是使用循環測試更準確,另外一個緣由是函數定義在本地做用域了
JSLitmus.test('function overhead', function(count) {
  var f = emptyFunction;
  while (count--) f();
});

// 測試Array.join()方法,而後咱們能夠看看它和字符串"+"操做的對比
JSLitmus.test('"hello" + "world" (non-looping)', function() {
  var a = "hello", b = "world", x;
  x = a+b;
});

// 循環測試Array.join()方法,而後咱們能夠看看它和字符串"+"操做的對比
JSLitmus.test('"hello" + "world"', function(count) {
  var a = "hello", b = "world", x;
  while(count--) x = a+b;
});

// 循環測試Array.join()方法,而後咱們能夠看看它和字符串"+"操做的對比
JSLitmus.test('string join()', function(count) {
  var a = ['hello', 'world'];
  while (count--) a.join();
});

// Math.random()是快仍是慢呢?
JSLitmus.test('Math.random()', function(count) {
  while (count--) Math.random();
});

// 正則表達測試有多快呢?讓咱們來一探究竟
JSLitmus.test('RegExp.test()', function(count) {
  while (count--) /rl/.test('hello world');
});

// 呵呵,若是在循環的外面定義正則表達式對象會有幫助嗎?
JSLitmus.test('cached RegExp.test()', function(count) {
  var re = /rl/;
  while (count--) re.test('hello world');
});

// 新建Date對象的速度怎樣?是快仍是慢?
JSLitmus.test('new Date()', function(count) {
  while (count--) new Date();
});

// 若是咱們把Dete對象設置到元素的innerHTML中的速度如何?
// 由於這個操做必定很慢,因此就不須要循環測試了
JSLitmus.test('set Element.innerHTML', function() {
  document.getElementById('test_element').innerHTML = new Date();
});

// 測試一個數組的建立,這個能夠做爲一個參照物
JSLitmus.test('new Array()', function(count) {
  while (count--) {var a = [];}
});

測試結果

其餘測試-測試結果

分析總結

圖中,Infinity的測試表明很是快,其中,空函數的調用,字符串的"+"的拼接都很是快。
Math.random()與新建一個數組也比較快。
正則表達式測試,數組的join,新建日期,稍微慢了些。
最後,設置innerHTML的dom操做最慢。

更多

web性能優化--高性能javascript

相關文章
相關標籤/搜索