深入理解Javascript中的循环优化


Posted in Javascript onNovember 09, 2013

循环是大多数编程语言都具备的基本功能,JS也不例外,不同之处在于JS是解释型语言,运行于浏览器环境中,客户端的软硬件条件会对JS执行效率产生很大的影响。然而客户端环境对于开发者是未知、多样的,并且难以改变,所以优化代码质量是提高代码效率的主要途径。
JS代码中,循环是比较容易导致性能问题的因素。理解循环特性进而有针对性地进行优化也许会带来不错的性能提升。
for、while、do-while循环:
这三种循环本身的循环效率相差不多,所以只要根据适合的应用场景选择即可。
以for循环为例:

var aValues = ["a", "b", "c", "d"];
for(var i = 0; i < aValues.length; i += 1){
 fDoSomethingA(aValues[i]);
 fDoSomethingA(aValues[i]);
}

上面例子中每次循环都要比较i与数组的长度,所以每次都要重新读取数组长度,由如果数组长度在循环中是不变的,这样做就没有必要,我们可以使用局部变量代替length的读取。同理,例子中,aValues[i]由于被读取两次以上,我们也可以将它赋值给局部变量:
var aValues = ["a", "b", "c", "d"], nLength = aValues.length;
 for(var i = 0, sValue; i < nLength; i += 1){
 sValue = aValues[i];
 fDoSomethingA(sValue);
 fDoSomethingB(sValue);
 }

如果循环的业务逻辑对循环顺序不敏感,可以尝试倒序循环,即将计数器递减到0。
var aValues = ["a", "b", "c", "d"], nLength = aValues.length;
 for(var i = nLength, sValue; i -= 1;){
 sValue = aValues[i];
 fDoSomethingA(sValue);
 fDoSomethingB(sValue);
 }

使用这种方式计数器默认与0进行比较,连局部变量比较都省略了,理论上也能提高效率。
for-in循环:
for-in循环更像在穷举,他用来遍历对象属性,我们知道对象属性的查找会一直延续到原型链顶端,这将大大降低循环效率。for-in循环的写法上没有什么优化空间,需要在使用时遵循一定原则:尽量只在遍历数据型对象的时候才使用for-in循环。
如果遍历对象的属性是明确的,可以使用数组循环替代。
例如遍历一个联系人对象:
var aContact = ["N", "FN", "EMAIL;PREF", ...];
 for(var i = aContact.length; i -= 1;){
 fDoSomething(aContact[i]);
 }
 

Duff策略
Duff策略的主要原理是通过展开循环减少次数来提高效率。例如
一个普通循环:
for(var i = aValues.length; i -= 1){
 fDoSomething(aValues[i]);
 }
 

如果aValues.length == N,写成以下这种方式的效率将比循坏来的高:
fDoSomething(aValues[0]);
 fDoSomething(aValues[1]);
 fDoSomething(aValues[2]);
 fDoSomething(aValues[3]);
 ...
 ...
 fDoSomething(aValues[N-1]);

但如果N很大,这种写法就不现实,而Duff策略是一种适中的循环展开策略。
近日在网易邮箱通讯录联系人的初始化循环中加入了Duff策略:
var nLength = aContacts.length,
// 总轮数
 nRounds = Math.floor( nLength / 8),
// 额外余量
 nLeft = nLength % 8,
i = 0;
// 先处理余量
 if(nLeft){
 do{
 fFormat(aContacts[i ++]);
 }while(-- nLeft)
}
// 每轮执行8次格式化
 if(nRounds){
 do{
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 }while(-- nRounds)
 }

如上所示,每轮循环可以执行8个联系人数据的格式化操作,还有一轮循环用于处理余下的联系人。由此可见,在联系人较多的情况下总的循环次数大大降低,可以降低循环的消耗。另外,8是Duff策略提出的最优值。
实际测试时发现在IE下可以带来10-20%以上的性能提升,而非IE浏览器中几乎看不到区别。
结束语:在测试过程中发现非IE浏览器下,优化后和优化前的效率差距并不是很大,甚至可以忽略,这说明这些浏览器的JS引擎对
Javascript 相关文章推荐
基于jQuery的history历史记录插件
Dec 11 Javascript
JavaScript var声明变量背后的原理示例解析
Oct 12 Javascript
比较不错的JS/JQuery显示或隐藏文本的方法
Feb 13 Javascript
什么是 AngularJS?AngularJS简介
Dec 06 Javascript
Javascript json object 与string 相互转换的简单实现
Sep 27 Javascript
Angular4实现鼠标悬停3d倾斜效果
Oct 25 Javascript
vue实现模态框的通用写法推荐
Feb 26 Javascript
JavaScript解析JSON数据示例
Jul 16 Javascript
过滤器vue.filters的使用方法实现
Sep 18 Javascript
node.js通过url读取文件
Oct 16 Javascript
Vue2.0 ES6语法降级ES5的操作
Oct 30 Javascript
vue router-link 默认a标签去除下划线的实现
Nov 06 Javascript
原生JS可拖动弹窗效果实例代码
Nov 09 #Javascript
当鼠标移动时出现特效的JQuery代码
Nov 08 #Javascript
window.onresize 多次触发的解决方法
Nov 08 #Javascript
javascript阻止scroll事件多次执行的思路及实现
Nov 08 #Javascript
setTimeout和setInterval的深入理解
Nov 08 #Javascript
如何获取select下拉框的值(option没有及有value属性)
Nov 08 #Javascript
jquery ajax修改全局变量示例代码
Nov 08 #Javascript
You might like
回答PHPCHINA上的几个问题:URL映射
2007/02/14 PHP
smarty 缓存控制前的页面静态化原理
2013/03/15 PHP
php对图像的各种处理函数代码小结
2013/07/08 PHP
php设置允许大文件上传示例代码
2014/03/10 PHP
PHP实现的连贯操作、链式操作实例
2014/07/08 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
2017/02/03 PHP
Kindeditor编辑器添加图片上传水印功能(php代码)
2017/08/03 PHP
jQueryUI如何自定义组件实现代码
2010/11/14 Javascript
js关于命名空间的函数实例
2015/02/05 Javascript
js制作带有遮罩弹出层实现登录注册表单特效代码分享
2015/09/05 Javascript
Bootstrap实现下拉菜单效果
2016/04/29 Javascript
js判断是否为空和typeof的用法(详解)
2016/10/07 Javascript
jQuery通过改变input的type属性实现密码显示隐藏切换功能
2017/02/08 Javascript
H5实现中奖记录逐行滚动切换效果
2017/03/13 Javascript
浅谈webpack4.x 入门(一篇足矣)
2018/09/05 Javascript
详解Vue项目部署遇到的问题及解决方案
2019/01/11 Javascript
Angular CLI 使用教程指南参考小结
2019/04/10 Javascript
Layer.js实现表格溢出内容省略号显示,悬停显示全部的方法
2019/09/16 Javascript
Vue SPA 初次进入加载动画实现代码
2019/11/14 Javascript
python 写入csv乱码问题解决方法
2016/10/23 Python
查看python安装路径及pip安装的包列表及路径
2019/04/03 Python
python scatter函数用法实例详解
2020/02/11 Python
python json 递归打印所有json子节点信息的例子
2020/02/27 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
2020/05/18 Python
通过实例简单了解python yield使用方法
2020/08/06 Python
python实现AHP算法的方法实例(层次分析法)
2020/09/09 Python
Data URI scheme详解和使用实例及图片base64编码实现方法
2014/05/08 HTML / CSS
html svg生成环形进度条的实现方法
2019/09/23 HTML / CSS
澳大利亚顶级美发和美容贸易超市:glamaCo
2020/01/19 全球购物
DJI全球:DJI Global
2021/03/15 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
幼儿教师工作感言
2014/02/14 职场文书
《神奇的克隆》教学反思
2014/04/10 职场文书
《歌唱二小放牛郎》教学反思
2014/04/19 职场文书
小学三年级班主任工作经验交流材料
2015/11/02 职场文书
假如给我三天光明:舟逆水而行,人遇挫而达 
2019/10/29 职场文书