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();  
    });  
});  

非常漂亮,不是吗。对于异步操作来说,上面代码是没有问题的,但如果其中某些操作是同步的,在resumeiterator这两个函数不停地互相调用可能会造成堆栈溢出,解决方法是用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

posted @ 2011-03-12 02:00  aj3423  阅读(605)  评论(0编辑  收藏  举报