setTimeout in for-loop does not print consecutive values
我有这个剧本:
1 2 3 | for (var i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 100); } |
但
有没有一种方法可以在不将函数写入字符串的情况下传递
您必须为每个超时函数安排一个单独的"i"副本。
1 2 3 4 5 6 | function doSetTimeout(i) { setTimeout(function() { alert(i); }, 100); } for (var i = 1; i <= 2; ++i) doSetTimeout(i); |
如果您不这样做(在这个相同的想法上还有其他的变化),那么每个计时器处理程序函数将共享相同的变量"i"。循环完成后,"i"的值是多少?它是3!通过使用中介函数,可以复制变量的值。由于超时处理程序是在该副本的上下文中创建的,所以它有自己的私有"i"可供使用。
edit&mdash;随着时间的推移,出现了一些注释,其中明显存在一些混淆,即设置一些超时会导致处理程序同时启动。重要的是要了解设置计时器的过程,调用
因此,如果发出了一系列超时请求,就像在op和我的答案中的代码一样,并且每个请求的时间延迟值都是相同的,那么一旦经过了一定的时间,所有的计时器处理程序都将被快速连续地逐个调用。
如果您需要的是每隔一段时间调用处理程序,那么您可以使用
1 2 3 4 5 | function doScaledTimeout(i) { setTimeout(function() { alert(i); }, i * 5000); } |
(使用
更新
在2018年,这里有一个更简单的选择。由于新的功能可以在比函数更窄的范围内声明变量,因此如果修改原始代码,则可以工作:
1 2 3 | for (let i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 100); } |
与
可以使用立即调用的函数表达式(IIFE)在
1 2 3 4 5 | for (var i = 1; i <= 3; i++) { (function(index) { setTimeout(function() { alert(index); }, i * 1000); })(i); } |
这是因为!
解决方案是通过使用执行的自函数(匿名的一个或更好的IIFE)为每个迭代声明一个范围,并在其中包含一个i的副本,如下所示:
1 2 3 4 5 6 7 8 9 10 | for (var i = 1; i <= 2; i++) { (function(){ var j = i; setTimeout(function() { console.log(j) }, 100); })(); } |
更干净的那个
1 2 3 4 5 6 7 8 9 | for (var i = 1; i <= 2; i++) { (function(i){ setTimeout(function() { console.log(i) }, 100); })(i); } |
在每个迭代中使用一个IIFE(自执行函数)为每个迭代创建了一个新的范围。迭代,这给了超时函数回调机会关闭每个迭代的新范围,其中一个迭代有一个变量其中包含每个迭代的权限值,供我们访问。
因为javascript变量只有函数作用域,所以解决方案是将循环变量传递给设置超时的函数。您可以声明和调用这样的函数:
1 2 3 4 5 | for (var i = 1; i <= 2; i++) { (function (x) { setTimeout(function () { alert(x); }, 100); })(i); } |
可以使用setTimeout的额外参数将参数传递给回调函数。
1 2 3 | for (var i = 1; i <= 2; i++) { setTimeout(function(j) { alert(j) }, 100, i); } |
注意:这在IE9及以下浏览器上不起作用。
回答?
我使用它来制作动画,将项目添加到购物车-购物车图标从产品"添加"按钮浮动到购物车区域,单击时:
1 2 3 4 5 6 7 | function addCartItem(opts) { for (var i=0; i<opts.qty; i++) { setTimeout(function() { console.log('ADDED ONE!'); }, 1000*i); } }; |
注:持续时间单位为单位乘以n epocs。
因此,从单击的时刻开始,动画开始epoc(每个动画的)是每一秒单位乘以项目数的乘积。
epoc:https://en.wikipedia.org/wiki/epoch_u(参考日期)
希望这有帮助!
你可以用
1 2 3 4 5 | for (var i = 1, j = 1; i <= 3; i++, j++) { setTimeout(function() { alert(this); }.bind(i), j * 100); } |
好吧,另一个基于科迪答案的工作解决方案是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function timedAlert(msg, timing){ setTimeout(function(){ alert(msg); }, timing); } function yourFunction(time, counter){ for (var i = 1; i <= counter; i++) { var msg = i, timing = i * time * 1000; //this is in seconds timedAlert (msg, timing); }; } yourFunction(timeInSeconds, counter); // well here are the values of your choice. |
一旦我解决了这个问题,我也有同样的问题。
假设我要12次延迟,间隔2秒
1 2 3 4 5 6 7 8 9 10 11 12 13 | function animate(i){ myVar=setTimeout(function(){ alert(i); if(i==12){ clearTimeout(myVar); return; } animate(i+1) },2000) } var i=1; //i is the start point 1 to 12 that is animate(i); //1,2,3,4..12 will be alerted with 2 sec delay |
真正的解决方案就在这里,但是您需要熟悉PHP编程语言。为了达到您的目的,您必须混合使用php和javascript命令。
注意:
1 2 3 4 5 6 7 | <?php for($i=1;$i<=3;$i++){ echo"<script language='javascript' > setTimeout(function(){alert('".$i."');},3000); "; } ?> |
它确实能满足你的需要,但是要小心如何在php变量和javascript变量。