如何提高数组循环的效率 - 倒序循环、Duff`s Device、异步迭代
>倒序循环可以略微的提升普通迭代的性能,如下:
/* * 一种可以提高循环效率的方法,倒序遍历,同步模式 */ var reverseFor = function(arr, handler){ for(var i = arr.length; i --;){ // 传入三个参数,当前数组项的值,索引,原始数组 handler(arr[i], i, arr); } };
>Duff`s Device迭代优化算法着重减少总工作量的迭代次数,如下(非原创,但已修复):
/* * Duff's Device 经典实现,同步模式,目的是减少迭代次数 */ var duffDevFor = function(arr, handler){ var length = arr.length; // 下舍入 var times = Math.ceil(length / 8), start = length % 8, inx = 0; do{ switch(start){ case 0 : handler(arr[inx ++], inx - 1, arr); case 7 : handler(arr[inx ++], inx - 1, arr); case 6 : handler(arr[inx ++], inx - 1, arr); case 5 : handler(arr[inx ++], inx - 1, arr); case 4 : handler(arr[inx ++], inx - 1, arr); case 3 : handler(arr[inx ++], inx - 1, arr); case 2 : handler(arr[inx ++], inx - 1, arr); case 1 : handler(arr[inx ++], inx - 1, arr); } start = 0;//归位 }while(-- times) };
但是上面的实现是最初的实现,还可以通过去掉switch语句来进一步提升效率:
/* * 优化后的 Duff's Device,同步模式,目的是减少迭代次数 */ var duffDevBetFor = function(arr, handler){ var length = arr.length; var inx = 0; // 余数循环 var remainder = length % 8; while(remainder){ handler(arr[inx ++], inx - 1, arr); remainder --; } // 主循环 var times = Math.floor(length / 8); while(times){ handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); handler(arr[inx ++], inx - 1, arr); times --; } };
>异步迭代:
/** * 异步迭代器 * * @param {Object} opt * * @param {Number} opt.from 起始数字 * @param {Number} opt.to 结束数字(可正可负,为负的时候,step相应的也是复数) * @param {Number} opt.step 每一次迭代的步子大小 * @param {Number} opt.iterate 在每一次interval之中,迭代多少次,默认是1次 * @param {Number} opt.interval 时间间隔,毫秒记 * @param {Function} opt.stepCallback 每一此迭代处理的调用函数,会传入每次迭代的index * @param {Function} opt.finalCallBack 全部结束后的回调函数,传入最后一次迭代的index */ var asyncFor = function( /*{from : , to : , step : , iterate : , interval : , stepCallback : , finalCallBack : }*/ opt ){ var from = opt.from, to = opt.to, iterate = opt.iterate || 1, positive = opt.step > 0, over = false; beStop = function(){ // 等于-1的时候,条件不满足 return positive ? ( from == to ? 1 : from > to ? 0 : -1 ) : ( from == to ? 1 : from < to ? 0 : -1 ); }; // 第一次调用 main(); var timer = window.setInterval(function(){ main(); }, opt.interval); // 主循环体 function main(){ // 如果第一次调用main就已经全部执行完的话,在下次清除timer if(over){ window.clearInterval(timer); return; } while(iterate){ var temp = beStop(); if(!(temp == -1)){ // 结束条件满足 window.clearInterval(timer); // 如果from == to,需要调用一次stepCallback if(temp == 1) if(opt.stepCallback) opt.stepCallback(from); if(opt.finalCallBack) opt.finalCallBack( temp == 0 ? (from -= opt.step) : from ); over = true; // 跳出循环 break; } if(opt.stepCallback) opt.stepCallback(from); from += opt.step; iterate --; } // 归位 iterate = opt.iterate || 1; }; };
那么如何使用呢?
asyncFor({ from: 1, to: 300, step: 2, interval: 10, iterate: 10, stepCallback: function(inx){ console.log(inx); }, finalCallBack: function(finalIndex){ console.log(finalIndex + '-End Index.'); } });
作为常用的工具函数 - -