深入理解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扩展插件Validate—4设置错误提示的样式
Sep 05 Javascript
easyui Droppable组件实现放置特效
Aug 19 Javascript
javascript中return,return true,return false三者的用法及区别
Nov 17 Javascript
jQuery基础的工厂函数以及定时器的经典实例分析
May 20 Javascript
js 创建对象 经典模式全面了解
Aug 16 Javascript
BootStrap中关于Select下拉框选择触发事件及扩展
Nov 22 Javascript
利用node.js写一个爬取知乎妹纸图的小爬虫
May 03 Javascript
详解Vue.use自定义自己的全局组件
Jun 14 Javascript
vue通过点击事件读取音频文件的方法
May 30 Javascript
vue-cli3搭建项目的详细步骤
Dec 05 Javascript
Vue分页插件的前后端配置与使用
Oct 09 Javascript
vue cli 3.0通用打包配置代码,不分一二级目录
Sep 02 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二分查找算法示例【递归与非递归方法】
2016/09/29 PHP
PHP常见的序列化与反序列化操作实例分析
2019/10/28 PHP
Cookie跨域问题解决方案代码示例
2020/11/24 PHP
用js实现计算加载页面所用的时间
2010/04/02 Javascript
JavaScript高级程序设计(第3版)学习笔记9 js函数(下)
2012/10/11 Javascript
编写js扩展方法判断一个数组中是否包含某个元素
2013/11/08 Javascript
jquery制作弹窗提示窗口代码分享
2014/03/02 Javascript
一张表格告诉你windows.onload()与$(document).ready()的区别
2014/05/16 Javascript
jquery对象访问是什么及使用方法介绍
2016/05/03 Javascript
JavaScript的MVVM库Vue.js入门学习笔记
2016/05/03 Javascript
EasyUI布局 高度自适应
2016/06/04 Javascript
vue环境搭建简单教程
2017/11/07 Javascript
浅谈React中组件间抽象
2018/01/27 Javascript
angularJs中$http获取后台数据的实例讲解
2018/08/08 Javascript
大转盘抽奖小程序版 转盘抽奖网页版
2020/04/16 Javascript
javascript中的数据类型检测方法详解
2019/08/07 Javascript
js实现漂亮的星空背景
2019/11/01 Javascript
javascript 函数的暂停和恢复实例详解
2020/04/25 Javascript
js将日期格式转换为YYYY-MM-DD HH:MM:SS
2020/09/18 Javascript
Python 16进制与中文相互转换的实现方法
2018/07/09 Python
Python3 利用requests 库进行post携带账号密码请求数据的方法
2018/10/26 Python
python时间序列按频率生成日期的方法
2019/05/14 Python
Python3匿名函数lambda介绍与使用示例
2019/05/18 Python
Django models.py应用实现过程详解
2019/07/29 Python
python能在浏览器能运行吗
2020/06/17 Python
python归并排序算法过程实例讲解
2020/11/04 Python
利用CSS3的3D效果制作正方体
2020/03/10 HTML / CSS
吉力贝官方网站:Jelly Belly
2019/03/11 全球购物
个人求职信范文分享
2014/01/31 职场文书
公司合作意向书
2014/04/01 职场文书
检察机关个人对照检查材料
2014/09/15 职场文书
人事主管岗位职责
2015/02/04 职场文书
2015年护士长个人工作总结
2015/04/24 职场文书
重阳节主题班会
2015/08/17 职场文书
2016十一国庆节慰问信
2015/12/01 职场文书
jQuery实现影院选座订座效果
2021/04/13 jQuery