在继续之前,我需要一个等待异步调用的循环.就像是:
for ( /* ... */ ) {
someFunction(param1, praram2, function(result) {
// Okay, for cycle could continue
})
}
alert("For cycle ended");
Run Code Online (Sandbox Code Playgroud)
我怎么能这样做?你有什么想法?
Ivo*_*zel 182
如果阻止脚本,则无法在JavaScript中混合同步和异步,阻止浏览器.
你需要在这里采用完整的事件驱动方式,幸运的是我们可以隐藏丑陋的东西.
编辑:更新了代码.
function asyncLoop(iterations, func, callback) {
var index = 0;
var done = false;
var loop = {
next: function() {
if (done) {
return;
}
if (index < iterations) {
index++;
func(loop);
} else {
done = true;
callback();
}
},
iteration: function() {
return index - 1;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
Run Code Online (Sandbox Code Playgroud)
这将为我们提供异步loop,您当然可以进一步修改它以获取例如检查循环条件等的函数.
现在进行测试:
function someFunction(a, b, callback) {
console.log('Hey doing some stuff!');
callback();
}
asyncLoop(10, function(loop) {
someFunction(1, 2, function(result) {
// log the iteration
console.log(loop.iteration());
// Okay, for cycle could continue
loop.next();
})},
function(){console.log('cycle ended')}
);
Run Code Online (Sandbox Code Playgroud)
并输出:
Hey doing some stuff!
0
Hey doing some stuff!
1
Hey doing some stuff!
2
Hey doing some stuff!
3
Hey doing some stuff!
4
Hey doing some stuff!
5
Hey doing some stuff!
6
Hey doing some stuff!
7
Hey doing some stuff!
8
Hey doing some stuff!
9
cycle ended
Run Code Online (Sandbox Code Playgroud)
wil*_*age 44
我简化了这个:
功能:
var asyncLoop = function(o){
var i=-1;
var loop = function(){
i++;
if(i==o.length){o.callback(); return;}
o.functionToLoop(loop, i);
}
loop();//init
}
Run Code Online (Sandbox Code Playgroud)
用法:
asyncLoop({
length : 5,
functionToLoop : function(loop, i){
setTimeout(function(){
document.write('Iteration ' + i + ' <br>');
loop();
},1000);
},
callback : function(){
document.write('All done!');
}
});
Run Code Online (Sandbox Code Playgroud)
示例: http ://jsfiddle.net/NXTv7/8/
什么@Ivo已经提出了一个更清洁的替代将是一个异步方法队列,假设你只需要进行一个异步调用的集合.
(请参阅Dustin Diaz的这篇文章以获得更详细的解释)
function Queue() {
this._methods = [];
this._response = null;
this._flushed = false;
}
(function(Q){
Q.add = function (fn) {
if (this._flushed) fn(this._response);
else this._methods.push(fn);
}
Q.flush = function (response) {
if (this._flushed) return;
this._response = response;
while (this._methods[0]) {
this._methods.shift()(response);
}
this._flushed = true;
}
})(Queue.prototype);
Run Code Online (Sandbox Code Playgroud)
您只需创建一个新实例Queue,添加所需的回调,然后使用异步响应刷新队列.
var queue = new Queue();
queue.add(function(results){
for (var result in results) {
// normal loop operation here
}
});
someFunction(param1, param2, function(results) {
queue.flush(results);
}
Run Code Online (Sandbox Code Playgroud)
此模式的另一个好处是您可以向队列添加多个功能,而不只是一个.
如果你有一个包含迭代器函数的对象,你可以在幕后添加对这个队列的支持,并编写看起来是同步的代码,但不是:
MyClass.each(function(result){ ... })
Run Code Online (Sandbox Code Playgroud)
只需编写each将匿名函数放入队列而不是立即执行,然后在异步调用完成时刷新队列.这是一种非常简单而强大的设计模式.
PS如果您正在使用jQuery,那么您已经拥有了一个名为jQuery.Deferred的异步方法队列.