javascript 异步循环 - asyncEach
来自
http://blog.jcoglan.com/2010/08/30/the-potentially-asynchronous-loop/
(可能已被墙)
写程序时候经常会碰到这种情况,有一个队列,对这个队列进行一次操作会相当消耗性能,因此需要对队列中每个元素独立进行操作,一个接一个。如果这个操作是阻塞的话 用一个for循环就搞定了,如果是异步操作呢。
比如,有一个url数组,需要轮流访问每一个url,上一个返回后才进行下一个
listOfUrls.forEach(function(url) { $.get(url, function(response) { // handle response }); });
以上代码显然是不满足要求的,所有请求将一次发送出去,而不是一个接一个。下面介绍这样的异步forEach:
Array.prototype.asyncEach = function(iterator) { var list = this, n = list.length, i = - 1; var resume = function() { i += 1; if (i === n) return; iterator(list[i], resume); }; resume(); };
以上代码展示了这种异步模型,对于先前url数组的例子,就可以这样:
listOfUrls.asyncEach(function(url, resume) { $.get(url, function(response) { // handle response resume(); }); });
非常漂亮,不是吗。对于异步操作来说,上面代码是没有问题的,但如果其中某些操作是同步的,在resume和iterator这两个函数不停地互相调用可能会造成堆栈溢出,解决方法是用setTimeout来迭代:
Array.prototype.asyncEach = function(iterator) { var list = this, n = list.length, i = - 1; var iterate = function() { i += 1; if (i === n) return; iterator(list[i], resume); }; var resume = function() { setTimeout(iterate, 1); }; resume(); };
setTimeout会把每次迭代操作的调用堆栈独立开,这样就不会溢出了。
ps:虽然以上setTimeout的时间参数设为0毫秒,还会有10ms左右的延时,100次迭代就会造成1秒左右的延时,对一些苛刻要求时间的应用是一个浪费,解决方法是用setZeroTimeout代替setTimeout
这是下一篇介绍的 setZeroTimeout