这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
循环处理是最常见的编程模式之一,也是提升性能必须关注的要点之一。本文将对此进行介绍。具有很好的参考价值,下面跟着小编一起来看下吧
循环处理是最常见的编程模式之一,也是提升性能必须关注的要点之一。
常见的优化方案有:
①JavaScript 的四种循环 (for、do-while、while、for-in) 中,for-in 循环比其他几种明显要慢。由于每次迭代操作会同时搜索实例或原型属性,for-in 循环的每次迭代都会产生更多的开销,所以比其他类型要慢。因此遍历一个属性数量有限的已知属性列表,可以这样优化:
- var props = ['prop1', 'prop2'],
- i = 0;
- whlie(i < props.length) {
- precess(object[props[i++]]);
- }
该代码只关注给定的属性,减少了循环的开销。
而对于,for、while、do-while。我在 chrome 下测试了一下,先创建一个大小为 1000000 的数组,每项乘 100 再叠加。
测试用例:
- window.onload = function(){
- var items = Array(1000000).join(',').split(',').map(function(item, index) {
- return index;
- });
- console.log(forCircle())
- console.log(whileCircle())
- console.log(doCircle())
- function forCircle(){
- console.profile();
- var currTime = new Date();
- var tal = 0;
- for(var i = 0;i < items.length; i++){
- tal = tal + process(items[i]);
- }
- console.profileEnd();
- console.log('forCircle用时:' + (new Date() - currTime) + 'ms');
- return tal;
- }
- function whileCircle(){
- console.profile();
- var currTime = new Date();
- var tal = 0;
- var j = 0;
- while (j < items.length){
- tal = tal + process(items[j++]);
- }
- console.profileEnd();
- console.log('whileCircle用时:' + (new Date() - currTime) + 'ms');
- return tal;
- }
- function doCircle(){
- console.profile();
- var currTime = new Date();
- var tal = 0;
- var k = 0;
- do{
- tal = tal + process(items[k++]);
- }while (k < items.length)
- console.profileEnd();
- console.log('doCircle用时:' + (new Date() - currTime) + 'ms');
- return tal;
- }
- function process(item){
- return item*100;
- }
- }
取某次测试结果:
平均来说,for 循环耗时 8ms,while 耗时 4ms,doWhile 耗时也是 4ms。for 是最慢的。
②减少迭代的工作量。把数组长度保存在局部变量中再遍历、颠倒数组的遍历顺序。
最常见的一个循环:
- for(var i = 0;i < items.length; i++){
- process(items[i]);
- }
- //
- var j = 0;
- while (j < items.length){
- process(items[j++]);
- }
- //
- var k = 0;
- do{
- process(items[k++]);
- }while (k < items.length)
在这个循环中,每次运行都会产生如下操作:
①查找一次属性(items.length)
②执行数值比较一次(i < items.length)
③查看控制条件是否为 true(i < items.length ==true)
④一次自增操作 (i++)
⑤一次数组查找 (items[i])
⑥一次函数调用(process(items[i]))
若把数组长度存到一个局部变量,那么就不需要每次都查找一次 items.length,也就提高了性能。
改为这样:
- for (var i = 0,
- len = items.length; i < len; i++) {
- process(items[i]);
- }
- //
- var j = 0,
- count = items.length;
- while (j < count) {
- process(items[j++]);
- }
- //
- var k = 0,
- num = items.length;
- do {
- process(items[k++]);
- } while ( k < num )
这样在大多数浏览器中能节省大概 25% 的运行时间(IE 中甚至可以节省 50%)。总的来说,循环次数大的情况下,运行时间确实有提升。取某次结果如下:
没有局部存量存储数组长度时:
有局部变量存储数组长度时:
③减少迭代次数,"Duffs Device" 即 "达夫设备" 循环体展开技术。适合于迭代次数较大的情况下。
摘抄一下书中达夫设备的基本理念:每次循环中最多可 8 次调用 process() 函数。循环迭代次数为元素总数除以 8。 因为总数不一定是 8 的整数倍, 所以 startAt 变量存放余数, 指出第一次循环中应当执行多少次 process()。比方说现在有 12 个元素,那么第一次循环将调用 process()4 次,第二次循环调用 process()8 次,用 2 次循环代替了 12 次循环。
基本模式:
- var iterations = Math.floor(items.length / 8),
- startAt = items.length % 8,
- i = 0;
- do {
- switch (startAt) {
- case 0:
- process(items[i++]);
- case 7:
- process(items[i++]);
- case 6:
- process(items[i++]);
- case 5:
- process(items[i++]);
- case 4:
- process(items[i++]);
- case 3:
- process(items[i++]);
- case 2:
- process(items[i++]);
- case 1:
- process(items[i++]);
- }
- startAt = 0;
- } while (-- iterations );
④基于函数的迭代比基于循环的迭代消耗性能更多。例:for 循环迭代与 forEach 函数迭代。
⑤优化 if-else,通常来说,switch 比 if-else 快,但是在判断条件较多时,使用查找表比 if-else 和 switch 都快。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持 phperz!
(adsbygoogle = window.adsbygoogle || []).push({});
来源: http://www.phperz.com/article/17/0704/327613.html