如何提高数组循环的效率 - 倒序循环、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.');
		}
	});

作为常用的工具函数   -  -

posted @ 2012-09-23 17:49  无墨来点睛  Views(2150)  Comments(0Edit  收藏  举报