Javascript嵌套循环与setTimeout

时间:2013-05-15 10:07:04

标签: javascript

这是一个后续问题:How to suspend JavaScript to allow render

我编写了一个函数,它执行一种暂停的for循环(允许在其间进行渲染):

function loop(count, callback){
    var counter = 0
    var iteration = function(){
        callback(counter)
        counter ++;
        if (counter < count){
            setTimeout(iteration, 0)
        }
    }
    iteration();
}

这很好用,例如loop(100, function(i){ console.log(i) } )。并允许浏览器在每次迭代之间进行渲染。

然而,在循环之后执行之后的问题时会出现问题,因为无法保证循环已完成。实际上,我认为它有的保证(因为主线程在第一次调用setTimeout之后继续)。嵌套这些循环时会加剧这种情况:

loop(10, function(i){
    loop(10, function(j){
        console.log(i + '-' + j)
    })
})
/// This definitely does not output the numbers in order...

我的用例是我正在运行一些模拟,每个模拟包含许多步骤,我想在每个模拟之间进行渲染。我是以错误的方式来做这件事的吗?

2 个答案:

答案 0 :(得分:2)

我将如何做到这一点:

编辑:阅读下面的OP评论后更新了答案:

function loop(count, callback, done) {
    var counter = 0;
    var next = function () {
        setTimeout(iteration, 0);
    };
    var iteration = function () {
        if (counter < count) {
            callback(counter, next);
        } else {
            done && done();
        }
        counter++;
    }
    iteration();
}

loop(100, function (i, next) {
    console.log(i);
    next();
})


loop(10, function (i, nextI) {
    loop(10, function (j, nextJ) {
        console.log(i + '-' + j);
        nextJ();
    }, nextI);
});

输出:

1
1-1
2
1-2
3
1-3
4
1-4
5
1-5
6
1-6
7
1-7
8
1-8
9
1-9
10
11
2-1 
<< ... >>
97
98
99

http://jsfiddle.net/4Rw2H/1/

loop函数可以有第三个参数done,它将在循环完成后运行(如果存在)。回调将有第二个参数next,当你想要运行下一次迭代时需要调用它。

这样,你可以在循环中调用异步函数,并让它按顺序运行。

答案 1 :(得分:0)

这似乎运作正常:

JSFIDDLE

var log = function (i) { console.log(i) },
    loop = function (count, callback) {
        callback(count);
        count--;
        count > 0 && arguments.callee(count, callback);
    }

loop(10, log);
console.log('end');
loop(5, log);