循環(huán)在我們的工作當(dāng)中是非常頻繁使用的,每個循環(huán)應(yīng)用的場景和適用的范圍都有一些區(qū)別,如果只是單純的比較哪個好哪個不好,應(yīng)該是沒有結(jié)果的,我這里做的性能對比,僅僅從循環(huán)讀取數(shù)值上的區(qū)別。主要包括:
forfor offor inforEachmapwhiledo whilesomefilter
這里使用webWork跑測試?yán)?
var worker = new Worker('work.js');
worker.postMessage("message");
this.addEventListener('message', function (e) {
let array = []
function initData() {
for (let i = 0; i < 1000000; i++) {
array.push(i)
}
}
initData()
console.log(array)
})
function testFunction(array) {
function testFor() {
let newArray = []
console.time('testFor')
for (let i = 0; i < array.length; i++) {
newArray.push(array[i])
}
console.timeEnd('testFor')
}
testFor()
function testForLen() {
let newArray = []
console.time('testForLen')
for (let i = 0, len = array.length; i < len; i++) {
newArray.push(array[i])
}
console.timeEnd('testForLen')
}
testForLen()
function testForIn() {
let newArray = []
console.time('testForIn')
for (let i in array) {
newArray.push(array[i])
}
console.timeEnd('testForIn')
}
testForIn()
function testForOf() {
let newArray = []
console.time('testForOf')
for (let i of array) {
newArray.push(array[i])
}
console.timeEnd('testForOf')
}
testForOf()
function testWhile() {
let newArray = []
console.time('testWhile')
let i = 0
while (i < array.length) {
newArray.push(array[i])
i++
}
console.timeEnd('testWhile')
}
testWhile()
function testDoWhile() {
let newArray = []
console.time('testDoWhile')
let i = 0
do {
newArray.push(array[i])
i++
} while (i < array.length);
console.timeEnd('testDoWhile')
}
testDoWhile()
function testMap() {
let newArray = []
console.time('testMap')
array.map((item) => {
newArray.push(item)
})
console.timeEnd('testMap')
}
testMap()
function testForeach() {
let newArray = []
console.time('testForeach')
array.forEach((item) => {
newArray.push(item)
})
console.timeEnd('testForeach')
}
testForeach()
function testFilter() {
let newArray = []
console.time('testFilter')
array.filter((item) => {
newArray.push(item)
})
console.timeEnd('testFilter')
}
testFilter()
function testSome() {
let newArray = []
console.time('testSome')
array.some((item) => {
newArray.push(item)
})
console.timeEnd('testSome')
}
testSome()
function testReduce() {
let newArray = []
console.time('testReduce')
array.reduce((all, a) => {
newArray.push(a)
}, 0)
console.timeEnd('testReduce')
}
testReduce()
}
1000000數(shù)據(jù)量測試


單位ms
5000000數(shù)據(jù)量測試


單位ms
10000000數(shù)據(jù)量測試


單位ms
20000000數(shù)據(jù)量測試


單位ms
測試環(huán)境
- CPU I7 7700K
- 內(nèi)存 16G 3200HZ
- 谷歌瀏覽器 80.0.3987.162(正式版本) (32 位)
- 系統(tǒng)win10專業(yè)版 64位
經(jīng)過上面的四輪對比:
- 性能最強(qiáng)的是
while,不管數(shù)據(jù)量的大小,一直穩(wěn)居第一 - 次之的
do while、for、for緩存length三者性能差距并不大,在數(shù)據(jù)量低于2千萬級別時:do while>for>for緩存length,上了兩千萬后:for緩存length>do while>for - 第三梯隊的
forEach、filter、some、reduce幾乎性能相當(dāng),只有filter一直是第五,其他三者輪流換位置:filter>forEach≈some≈reduce - 第四梯隊的
map、for of,兩者在數(shù)據(jù)量較低差距還是挺大的,當(dāng)數(shù)據(jù)量上了2000W,性能差距就沒那么大了:map>for of - 性能最差的就是
for in,基本上是最快的幾十倍的性能差距。
結(jié)果
while > do while ≈ for ≈ for緩存length > filter > forEach ≈ some ≈ reduce > map > for of > for in;
結(jié)果不代表這些循環(huán)方法的真實最終效果,只能代表在我的電腦上,這些方法測試讀取數(shù)組數(shù)據(jù)之間的差異,for of for in 更擅長對象,至于真實的效果就不太敢定論了,但是對于一般的循環(huán) for循環(huán)的性能肯定是非常好的,所以能夠用for循環(huán)就不要用map、forEach等遍歷方式,當(dāng)然如果真的對于性能要求并不那么高的項目,用什么的區(qū)別也不太大,畢竟在百萬級別的數(shù)據(jù)讀取差異上,時間差距也在幾十ms上,只是對于復(fù)雜大量數(shù)據(jù)上,就要多多注意,另外僅僅在for循環(huán)上,書寫方式的差異也有性能的差異。我自己也封裝過一個方法,包裹for循環(huán)使它能夠像forEach一樣的書寫方式,提高效率的同時也不影響性能。
/**
* 遍歷工具,dataset可以是數(shù)組和對象
* 回調(diào)函數(shù) handler( item, index|key, dataset)
* break----用return false
* continue --用return ture
* @param {Object | Array} dataset 對象或者數(shù)組
* @param {Function} handler 回調(diào)函數(shù)
* @param {Context} context 上下文this
* @return {Array} 返回對象或數(shù)組
*/
function each(dataset, handler, context) {
let callback = 'undefined' === typeof context ? handler : function (value, index, collection) {
return handler.call(context, value, index, collection);
};
let i, len, res;
if (dataset instanceof Array) { //數(shù)組
i = 0;
len = dataset.length;
for (; i < len; i++) {
res = callback(dataset[i], i, dataset);
if (false === res) {
break;
} else if (true === res) {
continue;
}
}
} else { //鍵值對象
let keys = getkeys(dataset);
i = 0;
len = keys.length;
for (; i < len; i++) {
res = callback(dataset[keys[i]], keys[i], dataset);
if (false === res) {
break;
} else if (true === res) {
continue;
}
}
}
/**
* 獲取對象自有屬性名
* @param {any} obj 對象
* @return {Array} 返回對象key數(shù)組
*/
function getkeys(obj) {
if (Object.prototype.toString.call(obj).slice(8, -1) !== 'Object') {
return [];
}
if (Object.keys) {
return Object.keys(obj);
}
}
return dataset;
}
示例
let object1 = {
ke: 1,
ke2: 2,
ke3: 3,
ke4: 5
}
each(object1, (item, key) => {
console.log(item)
})
let array = [1, 2, 3, 4, 5, 6, 7]
each(array, (item, key) => {
console.log(item)
})
let array = [1, 2, 3, 4, 5, 6, 7]
each(array, (item, key) => {
if(item>5){
return false //終止循環(huán)
}
console.log(item)
})