最初我有类似的东西(广告是一个数组):
for (var i = 0; i < ads.length; i++) {
asynchMeth(ad[i]);
}
asyncMeth是一个调用服务器的异步方法(我不能使它同步)。但我想asynchMeth(ad [i])将在asynchMeth(ad [i-1])完成后3秒开始。以下内容不起作用,但它提供了我正在寻找的内容:
isWorking = false; //Will be set to true whenever asyncMeth starts, to false when it ends.
var i = 0;
var timer = setInterval(3000, function() {
if(!isWorking){
if(i < ads.length){
asyncMeth(ads[i]);
i++;
}
else{
clearInterval(timer);
}
}
});
当我们调用具有不同/动态参数的函数时如何使用setInterval?
答案 0 :(得分:0)
我首先会向asyncMeth
添加一个回调函数,只要函数完成它正在执行的任何操作,就会调用它。否则,无法知道asyncMeth
是否已完成其工作。在你的例子中,你所拥有的与你想要的不一样!您希望ads[i]
在ads[i - 1]
完成后3秒处理{/ 1}}。相反,您拥有的代码是在ads[i]
开始处理之后3秒开始处理ads[i - 1]
的代码。通过回调asyncMeth
,您可以执行此操作:
(function work(i) {
if(i < ads.length) {
asyncMeth(ads[i], function() {
work(++i);
});
}
}(0);
这里有一个自调用函数,最初接受参数值0
。该值分配给参数i
。如果i
小于ads.length
,则表示我们仍有待处理的项目。因此,它将asyncMeth
作为参数调用ads[i]
。
但是我们也提供回调。在此回调中,我们告诉回调调用work
并增加i
的值。这意味着work
将开始处理下一个项目。
现在,您可以一个接一个地异步处理每个项目,直到i
等于ads.length
,此时您已经处理了所有项目。
修改强>
我注意到你提到你需要3秒钟的延迟。为此你可以这样做:
(function work(i) {
if(i < ads.length) {
asyncMeth(ads[i], function() {
setTimeout(function() {
work(++i);
}, 3000);
});
}
}(0);
这里唯一的区别是下一次迭代在最后一次完成后3秒发生。
答案 1 :(得分:0)
AFAICT,这里有两个答案:你要求的答案,以及你需要的答案。我会给两者以防万一其他人偶然发现Google的答案。
你应该做什么
看起来你正试图让一堆异步调用按顺序发生,并猜测它们会在大约三秒内回来。当然,如果事实证明这不是一个准确的猜测,那么你将遇到问题,所以你真正想要的是一个在请求回来的瞬间触发的函数。
有两种方法可以做到这一点 - 延续传递风格(又名回调地狱)或者承诺。前者在概念上更容易,但匆忙变得丑陋:
$http('url', function (data) {
//this function is called when the AJAX request comes back
//do something with data
$http('url2', function (data) {
//do something with second piece of data after request 2 loads
})
})
当你需要任意数字时,这会变得非常混乱。我的首选解决方案是递归的高阶函数,例如以下函数,尽管可以迭代地执行:
var launch = function f (i) {
return function (data) {
//do something with data
if (i <= urls.length - 1)
$http(urls[i+1], f(i+1))
}
}
//manually trigger the first one
launch(0)()
更清洁的方式是承诺。有数百个关于如何使用promises来清理异步代码的教程,here是如何为可变数量的请求执行此操作的示例。
您提出的问题
如果你真的想要发布一堆具有不同参数的超时,那么诀窍是关闭每一个超时以缓存i
的值。如果你这样做:
for (var i = 0; i < 20; i++) {
setTimeout(function () {
//i is 20 by the time this runs...
}, 1000)
}
然后函数的所有20次调用都会将i
视为20,这可能不是您想要的。
解决方案是:
for (var i = 0; i < 20; i++) {
setTimeout((function (j) {
//do something with j, which is a copy of the value of i for this iteration
})(i), 1000)
}
这个工作的原因是显式传递的原始函数参数(即数字)是通过值传递的,而通过闭包“传递”变量(这是在破碎的示例中发生的情况)通过引用传递,即使对于基元也是如此。