for循环中的setTimeout不会打印连续的值
我有这个脚本:
for (var i = 1; i <= 2; i++) { setTimeout(function() { alert(i) }, 100); }
但是, 3
是两次提醒,而不是1
然后2
。
有没有办法传递i
,而不写作函数作为一个string?
你必须为每个超时function安排一个独特的“i”副本。
function doSetTimeout(i) { setTimeout(function() { alert(i); }, 100); } for (var i = 1; i <= 2; ++i) doSetTimeout(i);
如果你不这样做(并且这个想法还有其他的变化),那么每个定时器处理函数将共享相同的variables“i”。 当循环完成时,“我”的价值是什么? 这是3! 通过使用中介function,variables的值的副本被做出。 由于超时处理程序是在该副本的上下文中创build的,因此它有自己的私有“我”使用。
编辑 – 随着时间的推移已经有一些评论,其中有一些混乱是显而易见的,因为设置一些超时会导致处理程序在同一时间所有的火灾。 重要的是要明白, 设置定时器的过程 – 对setTimeout()
的调用几乎没有时间。 也就是说,告诉系统“请在1000毫秒后调用这个函数”几乎立即返回,因为在定时器队列中安装超时请求的过程非常快。
因此,如果连续发生超时请求,就像在OP中的代码和我的答案中一样,并且延时值对于每个时间延迟值是相同的,那么一旦这个时间量已经过去,所有的定时器处理程序将陆续被连续调用。
如果你需要的是处理程序被间隔调用,你可以使用setInterval()
,这个setInterval()
和setTimeout()
完全一样,但是在请求数量的重复延迟之后会被触发不止一次,或者你可以build立超时,并乘以你的迭代计数器的时间值。 也就是说,修改我的示例代码:
function doScaledTimeout(i) { setTimeout(function() { alert(i); }, i * 5000); }
(有100
毫秒的超时,效果不会很明显,所以我把这个数字提高到了5000.) i
的值乘以基本延迟值,所以在循环中调用5次会导致延迟5秒,10秒,15秒,20秒和25秒。
您可以使用立即调用的函数expression式( IIFE )围绕setTimeout
创build闭包:
for (var i = 1; i <= 3; i++) { (function(index) { setTimeout(function() { alert(index); }, i * 1000); })(i); }
setTimeout
的函数参数正在closures循环variables。 循环在第一个超时之前结束并显示i
的当前值, i
3
。
由于JavaScriptvariables只有函数作用域,因此解决scheme是将循环variables传递给设置超时的函数。 你可以声明和调用这样的函数:
for (var i = 1; i <= 2; i++) { (function (x) { setTimeout(function () { alert(x); }, 100); })(i); }
这是因为 !
- 超时函数callback在循环完成后都运行良好。 实际上,随着定时器的到来,即使在每次迭代时都是setTimeout(..,0),所有这些函数callback仍然会在循环完成后严格运行,这就是为什么3被reflection了!
- 所有这两个函数,虽然它们在每个循环迭代中分别定义,但是在同一个共享的全局范围内closures,实际上只有一个我在其中。
该解决scheme通过使用一个自执行的函数(匿名一个或更好的IIFE )并在其中拥有一个i的副本来为每个迭代声明一个单独的范围,如下所示:
for (var i = 1; i <= 2; i++) { (function(){ var j = i; setTimeout(function() { console.log(j) }, 100); })(); }
更清洁的人会
for (var i = 1; i <= 2; i++) { (function(i){ setTimeout(function() { console.log(i) }, 100); })(i); }
在每次迭代中使用IIFE (自执行函数)为每次迭代创build了一个新的范围,这为我们的超时函数callback提供了一个机会,在每个迭代中closures一个新的范围,一个variables具有正确的per-迭代值让我们访问。
您可以使用额外的参数setTimeout将parameter passing给callback函数。
for (var i = 1; i <= 2; i++) { setTimeout(function(j) { alert(j) }, 100, i); }
注意:这不适用于IE9及以下的浏览器。
答案 ?
我使用它来添加项目到一个购物车的animation – 一个购物车图标浮动到购物车区域从产品“添加”button,当点击:
function addCartItem(opts) { for (var i=0; i<opts.qty; i++) { setTimeout(function() { console.log('ADDED ONE!'); }, 1000*i); } };
注意,持续时间以单位时间n epocs为单位 。
因此,从点击时刻开始,animation开始epoc(每个animation的)是每个一秒单位乘以项目数的乘积。
epoc : https : //en.wikipedia.org/wiki/Epoch_(reference_date )
希望这可以帮助!
那么,另一个基于Cody的答案,但更一般的工作解决scheme可以是这样的:
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.
你可以使用bind
方法
for (var i = 1, j = 1; i <= 3; i++, j++) { setTimeout(function() { alert(this); }.bind(i), j * 100); }
一旦我解决了这个问题,我也遇到了同样的问题。
假设我需要12秒延迟,间隔2秒
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
真正的解决scheme就在这里,但是您需要熟悉PHP编程语言。 你必须混合使用PHP和JAVASCRIPT命令才能达到你的目的。
注意这一点:
<?php for($i=1;$i<=3;$i++){ echo "<script language='javascript' > setTimeout(function(){alert('".$i."');},3000); </script>"; } ?>
它正是你想要的,但要小心如何使PHPvariables和JavaScript之间的关系。