深入理解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 相关文章推荐
this[] 指的是什么内容 讨论
Mar 24 Javascript
从sohu弄下来的flash中展示图片的代码
Apr 27 Javascript
Jquery插件编写简明教程
Mar 25 Javascript
js表格排序实例分析(支持int,float,date,string四种数据类型)
May 06 Javascript
JQuery EasyUI Layout 在from布局自适应窗口大小的实现方法
May 28 Javascript
bootstrap侧边栏圆点导航
Jan 11 Javascript
easyui关于validatebox实现多重规则验证的方法(必看)
Apr 12 Javascript
Vue兼容ie9的问题全面解决方案
Jun 19 Javascript
Js中使用正则表达式验证输入是否有特殊字符
Sep 07 Javascript
Nuxt升级2.0.0时出现的问题(小结)
Oct 08 Javascript
基于vue2.0实现仿百度前端分页效果附实现代码
Oct 30 Javascript
浅谈JavaScript闭包
Apr 09 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
发布一个迷你php+AJAX聊天程序[聊天室]提供下载
2007/07/21 PHP
php 判断网页是否是utf8编码的方法
2014/06/06 PHP
ThinkPHP3.1查询语言详解
2014/06/19 PHP
PHP后台微信支付和支付宝支付开发
2017/04/28 PHP
php微信公众号开发之二级菜单
2018/10/20 PHP
Javascript 不能释放内存.
2006/09/07 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
jQuery实现的表头固定效果实例【附完整demo源码下载】
2016/08/01 Javascript
bootstrap table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)代码分享
2017/01/24 Javascript
原生JS实现图片懒加载(lazyload)实例
2017/06/13 Javascript
js推箱子小游戏步骤代码解析
2018/01/10 Javascript
使用Vue构建可重用的分页组件
2018/03/26 Javascript
jQuery实现判断上传图片类型和大小的方法示例
2018/04/11 jQuery
vue 实现Web端的定位功能 获取经纬度
2019/08/08 Javascript
详解javascript中var与ES6规范中let、const区别与用法
2020/01/11 Javascript
vue总线机制(bus)知识点详解
2020/05/10 Javascript
vuejs element table 表格添加行,修改,单独删除行,批量删除行操作
2020/07/18 Javascript
jquery实现广告上下滚动效果
2021/03/04 jQuery
[42:20]2014 DOTA2华西杯精英邀请赛5 24 DK VS NewBee
2014/05/25 DOTA
[01:16:50]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第一场 3月7日
2021/03/11 DOTA
python 简单备份文件脚本v1.0的实例
2017/11/06 Python
python+matplotlib绘制饼图散点图实例代码
2018/01/20 Python
Python3.7 dataclass使用指南小结
2019/02/22 Python
如何使用Python抓取网页tag操作
2020/02/14 Python
python matplotlib包图像配色方案分享
2020/03/14 Python
python实现批量命名照片
2020/06/18 Python
意大利拉斐尔时尚购物网:Raffaello Network(支持中文)
2018/11/09 全球购物
Juice Beauty官网:有机美容产品,护肤与化妆品
2020/06/13 全球购物
Ooni英国官网:披萨烤箱
2020/05/31 全球购物
中间件分为哪几类
2012/03/14 面试题
开学典礼决心书
2014/03/11 职场文书
建国大业观后感600字
2015/06/01 职场文书
运动会开幕式新闻稿
2015/07/17 职场文书
八年级数学教学反思
2016/02/17 职场文书
MySQL主从搭建(多主一从)的实现思路与步骤
2021/05/13 MySQL
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android