Javascript如何在迭代列表操作中使用setTimeout
Javascript how to use setTimeout on an iterative list operation?
我想做这样的事情:
for(var i=0;i<aList.length;i++)
{
aList[i].doSomething();
sleep(500);
}
当然,javascript中没有睡眠功能,所以我尝试了以下操作:
for(var i=0;i<aList.length;i++)
{
setTimeout(function(){
aList[i].doSomething();
},500);
}
然而,现在它说aList[i]没有定义。由于匿名函数是一个闭包,它实际上是从外部函数的作用域中读取aList[i],因此当setTimeout中的函数运行时,i
已经发生了变化。
实现这一点的方法是什么?
模拟JavaScript1.7的let
的一个快速修复方法是将其封装在一个函数中:
for(var i=0; i < aList.length; i++) {
(function(i) {
setTimeout(function() {
aList[i].doSomething();
}, 500 * i); // <-- You need to multiply by i here.
})(i);
}
我还修复了一个小错误,在这个错误中,脚本将暂停500秒,然后执行所有这些错误。setTimeout
是非阻塞的。
这就是您可能想要的:
for(var i=0;i<aList.length;i++)
{
(function(i){
// Retain `i` in this scope, for use later (after timeout)
setTimeout(function(){
aList[i].doSomething();
}, 500 * i);
})(i);
}
您希望500 * i
使每一步都比上一步晚500ms,否则500ms后所有事情都会同时发生。请注意额外的包装函数——它本质上是捕获/保留i
的值。
变体之一:
var array = [/*elements*/],
i,
length = array.length,
loop = setInterval(function() {
array[i].doSomething();
i += 1;
if (i === length) {
clearInterval(loop);
}
}, 500);
只需在超时之前定义函数
for(var i=0; nextFunction = aList[i];i++) {
var waitAndDoSomething = function(func) {
return function() { func.doSomething(); }
};
setTimeout(waitAndDoSomething(nextFunction),500*i);
}
另一个可能的答案
在minitect的建议下,我开始考虑其他可能的解决方案。我觉得一个干净的解决方案是使用bind
String.prototype.doSomething = function() { alert(this); } // Just for testing
var aList = ['one', 'two', 'three']; // Just for testing
for(var i=0;obj = aList[i];i++) {
setTimeout(obj.doSomething.bind(obj),500*i);
}
然而,我不确定这在Razor Storm的问题中会有多好,因为我不知道aList[I]代表什么。
这能回答问题吗
我还想知道这是否是故意的行为。它实际上不会在执行之后休眠,而是设置时间。这可能是骗人的,但如果我们真的想执行一个函数,然后在下一个函数之前睡半秒钟,我们的时机就错了。相反,我会使用递归:
String.prototype.doSomething = function() { alert(this); }
var aList = ['one', 'two', 'three'];
var doNextSomething = function(index) {
if (!index) { index = 0 }
if (nextObject = aList[index]) {
nextObject.doSomething();
setTimeout(doNextSomething, 500, index + 1);
}
};
doNextSomething();
现在,它将在函数执行后等待500毫秒(在长时间运行的任务中很明显(。
不过,我认为发布的答案更多的是Razor Storm的想法。
在for循环之前执行以下操作:
var _aList = aList;
在循环中,您必须设置Timeout和延迟500*i.
因此,结果将是:
var _aList = aList;
for(var i=0;i<aList.length;i++)
{
(function(obj, index) {
setTimeout(function(){
obj.doSomething();
},500 * index);
})(aList[i], i);
}
相关文章:
- 如何使jQuery插件函数可调用以供独立使用,而不在集合上操作
- setInteval vs setTimeout
- Jquery菜单操作不稳定,定位不正确,存在一般错误
- 如何确定javascript已经完成了某些操作.ios上的
- 防止Alt+Shift默认操作或检测多种操作系统语言的Javascript
- 从JavaScript访问struts操作中的属性
- 如何在chrome扩展中存储数据/结果,以及如何使用setTimeout使其只被调用一次
- fluxxor向一个flux实例添加一组以上的操作
- Jquery表单验证插件-如果选中复选框,如何在提交时执行某些操作
- 操作放置在画布上的元素之间的连接
- 使用“+="操作人员
- Rails操作只调用一次,但我在ajax中每秒钟都调用一次
- Jquery未定义函数正在停止其他操作
- 如何操作iframe之外的元素
- 在 setTimeout() 函数中模拟 clearTimeout() 操作
- jQuery setTimeout:行上的第一个操作不起作用
- window.open在setTimeout内没有't执行该操作
- setTimeout延迟操作
- 在进入下一个循环迭代之前执行setTImeout操作
- Javascript如何在迭代列表操作中使用setTimeout