深入探究JavaScript中for循环的效率问题及相关优化
作者:bea
Underscore.js库 你一天(一周)内写了多少个循环了? var i;for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; doSomeWorkOn(someThing);} 这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。 var i, j;for(i = 0; i < someArray.length; i++) { var
Underscore.js库
你一天(一周)内写了多少个循环了?
var i;
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
doSomeWorkOn(someThing);
}
这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。
var i,
j;
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
for(j = 0; j < someThing.stuff.length; j++) {
doSomeWorkOn(someThing.stuff[j]);
}
}
你在扩展糟糕的代码,在你抛出一大堆if前,你已经精神错乱了。 我在两年里没有写一个循环(loop)。 “你在说什么?” 这是真的,一个冷笑话。其实不是一个都没有(好吧,我确实写了几个),因为我不写循环(loops),我的代码更容易理解。 怎么做的呢?
_.each(someArray, function(someThing) {
doSomeWorkOn(someThing);
})
或者更好一点:
_.each(someArray, doSomeWorkOn);
这就是underscorejs所做到的。干净,简单,易读,短,没有中间变量,没有成堆的分号,简单非常优雅。 这是另外一些例子。
var i,
result = [];
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
// 打到这,我已经手疼了
if(someThing.isAwesome === true) {
result.push(someArray[i]);
}
}
同样,一个使用循环浪费时间的典型用例。即便这些网站是宣传禁烟和素食主义的,看到这些代码我也感到义愤。看看简单的写法。
var result = _.filter(someArray, function(someThing) {
return someThing.isAwesome === true;
})
像underscore中的filter(过滤)的名字那样,随手写的3行代码就可以给你一个新的数组(array)。 或者你想把这些数组转换成另外一种形式?
var result = _.map(someArray, function(someThing) {
return trasformTheThing(someThing);
})
上面三个例子在日常生活中已经够用了,但这些功能还不足矣让underscore放到台面上。
var grandTotal = 0,
somePercentage = 1.07,
severalNumbers = [33, 54, 42],
i; // don't forget to hoist those indices;
for(i = 0; i < severalNumbers.length; i++) {
var aNumber = severalNumbers[i];
grandTotal += aNumber * somePercentage;
}
underscore版本
var somePercentage = 1.07,
severalNumbers = [33, 54, 42],
grandTotal;
grandTotal = _.reduce(severalNumbers, function(runningTotal, aNumber) {
return runningTotal + (aNumber * somePercentage);
}, 0)
这个刚开始看上去可能有点怪,我查了下关于reduce的文档,知道了它的存在。因为我拒绝使用循环,所以它是我的首选。上面这些东西仅仅是入门,underscorejs库还有一大堆牛B的功能。
30天不使用循环的挑战。
在一下一个30天里,不要使用任何循环,如果你看到一堆讨厌和粗糙的东西,用each或者map将他们替换掉。再用一点reducing。
你需要注意到,Underscore是通往函数式编程的。一种看得见,看不见的方式。一条很好的途径。
OurJS注*目前现代浏览器已经支持each, filter, map, reduce方法,但underscore库可以实现对旧版IE的兼容,下面是使用ES5原生方法写的例子:
[3,4,5,3,3].forEach(function(obj){
console.log(obj);
});
[1,2,3,4,5].filter(function(obj){
return obj < 3
});
[9,8,5,2,3,4,5].map(function(obj){
return obj + 2;
});
[1,2,3,4,5].reduce(function(pre, cur, idx, arr) {
console.log(idx); //4 个循环: 2-5
return pre + cur;
}); //15
//sort方法同样很有用
[9,8,5,2,3,4,5].sort(function(obj1, obj2){
return obj1 - obj2;
});
for in与for loop
有人提出for in的效率要比for loop(循环)的效率低非常多。现在我们测试一下在不同浏览器中使用for in, for loop和forEach在处理大数组时的效率究竟如何。
目前绝大部分开源软件都会在for loop中缓存数组长度,因为普通观点认为某些浏览器Array.length每次都会重新计算数组长度,因此通常用临时变量来事先存储数组长度,如:
for (var idx = 0, len = testArray.length; idx < len; idx++) {
//do sth.
}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
for (var idx = 0, len = testArray.length; idx < len; idx++) {
//do sth.
}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
测试代码如下,点击运行即可查看 HTML 代码
<h4 id="browser"></h4>
<table id="results" class="table"></table>
JavaScript 代码
function () {
//准备测试数据, 有200万条数据的大数组
var testArray = []
, testObject = {}
, idx
, len = 2000000
, tmp = 0
, $results = $("#results")
, $browser = $("#browser")
;
$browser.html(navigator.userAgent);
$results.html('');
for (var i = 0; i < len; i++) {
var number = Math.random(); //若希望加快运算速度可使用取整:Math.random() * 10 | 0
testArray.push(number);
testObject[i] = number;
}
$results.append('<tr><th>测试代码</th><th>计算结果</th><th>所需时间,毫秒</th></tr>');
//测试函数
var test = function(testFunc) {
var startTime
, endTime
, result
;
startTime = new Date();
tmp = 0;
testFunc();
endTime = new Date();
//计算测试用例(Test Case)运行所需要的时间
result = endTime - startTime;
$results.append('<tr><td><pre>{0}</pre></td><td>{1}</td><td>{2}</td></tr>'.format(testFunc.toString(), tmp | 0, result));
};
test(function() {
//测试for in 的效率
for (idx in testArray) {
tmp += testArray[idx]; //经测试,idx是string类型,可能是慢的原因之一
}
});
test(function() {
//测试for loop循环的效率
for (idx = 0, len = testArray.length; idx < len; idx++) {
tmp += testArray[idx];
}
});
test(function() {
//测试forEach的效率
testArray.forEach(function(data) {
tmp += data;
});
});
test(function() {
//测试不缓存Array.length时效率
for (idx = 0; idx < testArray.length; idx++) {
tmp += testArray[idx];
}
});
test(function() {
//测试使用{} (Object) 存健值对时,使用for in的效率如何
for (idx in testObject) {
tmp += testObject[idx];
}
});
test(function() {
//测试从{} Object查值时的效率如何(这里的健key值事先己知)
for (idx = 0, len = testArray.length; idx < len; idx++) {
tmp += testObject[idx];
}
});
}
运行 [需稍等片刻] 测试结果 测试结果可能因计算而异,这是在我机器上运行用,Firefox, Chrome, IE三者测试结果拼接的一张汇总。
以下是几个观察到的结论
for in比for loop慢非常多,在Chrome中至少慢20倍
FF对forEach(ES5)做了优化,性能比for loop还要好一点,但Chrome/IEn性能均较差
FF/Chrome缓存Array.length均比直接用时要慢一点。除IE最新版缓存后性能提升微乎其微(这一点非常意外)
在某些情况下,FF的JS引擎性能似乎比V8要好些
有用 | 无用
你一天(一周)内写了多少个循环了?
var i;
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
doSomeWorkOn(someThing);
}
这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。
var i,
j;
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
for(j = 0; j < someThing.stuff.length; j++) {
doSomeWorkOn(someThing.stuff[j]);
}
}
你在扩展糟糕的代码,在你抛出一大堆if前,你已经精神错乱了。 我在两年里没有写一个循环(loop)。 “你在说什么?” 这是真的,一个冷笑话。其实不是一个都没有(好吧,我确实写了几个),因为我不写循环(loops),我的代码更容易理解。 怎么做的呢?
_.each(someArray, function(someThing) {
doSomeWorkOn(someThing);
})
或者更好一点:
_.each(someArray, doSomeWorkOn);
这就是underscorejs所做到的。干净,简单,易读,短,没有中间变量,没有成堆的分号,简单非常优雅。 这是另外一些例子。
var i,
result = [];
for(i = 0; i < someArray.length; i++) {
var someThing = someArray[i];
// 打到这,我已经手疼了
if(someThing.isAwesome === true) {
result.push(someArray[i]);
}
}
同样,一个使用循环浪费时间的典型用例。即便这些网站是宣传禁烟和素食主义的,看到这些代码我也感到义愤。看看简单的写法。
var result = _.filter(someArray, function(someThing) {
return someThing.isAwesome === true;
})
像underscore中的filter(过滤)的名字那样,随手写的3行代码就可以给你一个新的数组(array)。 或者你想把这些数组转换成另外一种形式?
var result = _.map(someArray, function(someThing) {
return trasformTheThing(someThing);
})
上面三个例子在日常生活中已经够用了,但这些功能还不足矣让underscore放到台面上。
var grandTotal = 0,
somePercentage = 1.07,
severalNumbers = [33, 54, 42],
i; // don't forget to hoist those indices;
for(i = 0; i < severalNumbers.length; i++) {
var aNumber = severalNumbers[i];
grandTotal += aNumber * somePercentage;
}
underscore版本
var somePercentage = 1.07,
severalNumbers = [33, 54, 42],
grandTotal;
grandTotal = _.reduce(severalNumbers, function(runningTotal, aNumber) {
return runningTotal + (aNumber * somePercentage);
}, 0)
这个刚开始看上去可能有点怪,我查了下关于reduce的文档,知道了它的存在。因为我拒绝使用循环,所以它是我的首选。上面这些东西仅仅是入门,underscorejs库还有一大堆牛B的功能。
30天不使用循环的挑战。
在一下一个30天里,不要使用任何循环,如果你看到一堆讨厌和粗糙的东西,用each或者map将他们替换掉。再用一点reducing。
你需要注意到,Underscore是通往函数式编程的。一种看得见,看不见的方式。一条很好的途径。
OurJS注*目前现代浏览器已经支持each, filter, map, reduce方法,但underscore库可以实现对旧版IE的兼容,下面是使用ES5原生方法写的例子:
[3,4,5,3,3].forEach(function(obj){
console.log(obj);
});
[1,2,3,4,5].filter(function(obj){
return obj < 3
});
[9,8,5,2,3,4,5].map(function(obj){
return obj + 2;
});
[1,2,3,4,5].reduce(function(pre, cur, idx, arr) {
console.log(idx); //4 个循环: 2-5
return pre + cur;
}); //15
//sort方法同样很有用
[9,8,5,2,3,4,5].sort(function(obj1, obj2){
return obj1 - obj2;
});
for in与for loop
有人提出for in的效率要比for loop(循环)的效率低非常多。现在我们测试一下在不同浏览器中使用for in, for loop和forEach在处理大数组时的效率究竟如何。
目前绝大部分开源软件都会在for loop中缓存数组长度,因为普通观点认为某些浏览器Array.length每次都会重新计算数组长度,因此通常用临时变量来事先存储数组长度,如:
for (var idx = 0, len = testArray.length; idx < len; idx++) {
//do sth.
}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
for (var idx = 0, len = testArray.length; idx < len; idx++) {
//do sth.
}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
测试代码如下,点击运行即可查看 HTML 代码
<h4 id="browser"></h4>
<table id="results" class="table"></table>
JavaScript 代码
function () {
//准备测试数据, 有200万条数据的大数组
var testArray = []
, testObject = {}
, idx
, len = 2000000
, tmp = 0
, $results = $("#results")
, $browser = $("#browser")
;
$browser.html(navigator.userAgent);
$results.html('');
for (var i = 0; i < len; i++) {
var number = Math.random(); //若希望加快运算速度可使用取整:Math.random() * 10 | 0
testArray.push(number);
testObject[i] = number;
}
$results.append('<tr><th>测试代码</th><th>计算结果</th><th>所需时间,毫秒</th></tr>');
//测试函数
var test = function(testFunc) {
var startTime
, endTime
, result
;
startTime = new Date();
tmp = 0;
testFunc();
endTime = new Date();
//计算测试用例(Test Case)运行所需要的时间
result = endTime - startTime;
$results.append('<tr><td><pre>{0}</pre></td><td>{1}</td><td>{2}</td></tr>'.format(testFunc.toString(), tmp | 0, result));
};
test(function() {
//测试for in 的效率
for (idx in testArray) {
tmp += testArray[idx]; //经测试,idx是string类型,可能是慢的原因之一
}
});
test(function() {
//测试for loop循环的效率
for (idx = 0, len = testArray.length; idx < len; idx++) {
tmp += testArray[idx];
}
});
test(function() {
//测试forEach的效率
testArray.forEach(function(data) {
tmp += data;
});
});
test(function() {
//测试不缓存Array.length时效率
for (idx = 0; idx < testArray.length; idx++) {
tmp += testArray[idx];
}
});
test(function() {
//测试使用{} (Object) 存健值对时,使用for in的效率如何
for (idx in testObject) {
tmp += testObject[idx];
}
});
test(function() {
//测试从{} Object查值时的效率如何(这里的健key值事先己知)
for (idx = 0, len = testArray.length; idx < len; idx++) {
tmp += testObject[idx];
}
});
}
运行 [需稍等片刻] 测试结果 测试结果可能因计算而异,这是在我机器上运行用,Firefox, Chrome, IE三者测试结果拼接的一张汇总。
以下是几个观察到的结论
for in比for loop慢非常多,在Chrome中至少慢20倍
FF对forEach(ES5)做了优化,性能比for loop还要好一点,但Chrome/IEn性能均较差
FF/Chrome缓存Array.length均比直接用时要慢一点。除IE最新版缓存后性能提升微乎其微(这一点非常意外)
在某些情况下,FF的JS引擎性能似乎比V8要好些
有用 | 无用
猜你喜欢
您可能感兴趣的文章:
- dedecms页面如何获取会员状态的实例代码
- JavaScript隐式类型转换
- JavaScript正则表达式匹配 div style标签
- Angularjs整合微信UI(weui)
- 一步步教大家编写酷炫的导航栏js+css实现
- 原生javascript+css3编写的3D魔方动画旋扭特效
- 基于javascript html5实现3D翻书特效
- php基于redis处理session的方法
- 使用javascript插入样式
- jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)
- javascript实现数组去重的多种方法
- javascript实现PC网页里的拖拽效果
- Jquery实现简单的轮播效果(代码管用)
- node模块机制与异步处理详解
- JS中创建函数的三种方式及区别
- 使用jQuery操作HTML的table表格的实例解析
- Javascript数组Array方法解读
- GitHub上一些实用的JavaScript的文件压缩解压缩库推荐
- Javascript数组Array基础介绍