将 For-loop 与内部超时和关闭混淆
Confusing For-loop with timeout inside and closure
所以,我制作了一个容器 div,在里面 div 我有一个脚本动态创建 113 个 div 的 class 名称 [=33] =].现在,一切都井井有条了,我特地把那 113 div 做得非常小,大约 5X5 像素。然后我把它们放在容器里,让它们拼出一个标题。所有 div 都在一个名为 divs 的数组中。所以 divs 是一个有 113 个元素的数组。
现在事情变得混乱了,我想让那些 div 隐藏在浏览器的不可见区域后面,我通过提供 'fragments' 绝对定位并设置它们隐藏的样式来实现这一点,例如: divs[45].style.left = -600';
,在那之后,我创建了一个脚本 运行 a for-loop 在里面 for-loop 我想要每个小元素在延迟后返回到它的位置。但是,我不得不为此使用闭包,因为在 for-loop 中插入 SetTimeout()
很奇怪。
for (i = 0; i < divs.length; i++)
{
(function(j)
{
setTimeout(function ()
{
divs[j].style.left = divs[j].offsetLeft + 550;
}, Math.floor(Math.random() * 1000));
})(i); //Pass current value into self-executing anonymous function
}
我无法理解上面的代码。我以为写Math.floor(Math.random() * 1000)
的区域是指定延迟ms的。但是,如果我输入 1000,它将立即移动所有 113 个元素。我不明白这一点,它不应该在移动到数组中的下一个元素之前等待 1 秒吗?顺便说一下,代码运行良好,最终发生的是元素随机移动,给标题带来了非常酷的效果。闭包对我来说已经够混乱了,对我来说这似乎是非常奇怪的行为。
有人能解释一下为什么会发生这种情况吗?如果我取出 Math.floor(Math.random() * 1000)
,为什么所有元素都会同时移动,而不是简单地让一个元素大约每秒移动一次。 .. *
编辑
我的问题不是关于闭包,而是关于为什么取出 Math.floor(Math.random() * 1000)
并将其替换为“1000”,导致所有元素立即移动,而不是一个一个地间隔 1000 毫秒.
所有 setTimeout 都在(几乎)同时实例化,并且因为它们都有 1 秒的延迟,所以它们都在(几乎)同时启动。
如果要按顺序添加元素,则需要递归进行。如果您使用 for
循环,那么您将 "simultaneously" 安排一堆计时器。他们会同时开始倒计时,他们都会尽快结束,互不关心。
以下是如何按顺序安排计时器的示例:
var things = [1, 2, 3];
(function next(array) {
setTimeout(function () {
var item = array[0],
remaining = array.slice(1);
console.log(item);
if (remaining.length > 0) {
next(remaining);
}
}, 1000);
}(things));
如果您正在进行大量异步工作,或者如果您想处理类似于同步任务的异步任务,请尝试 Async。它提供了一些不错的循环机制:
async.eachSeries(things, function (thing, callback) {
setTimeout(function () {
console.log(thing);
callback();
}, 1000);
}, function () {
console.log('all done');
});
根据前面的回答,我很确定你已经理解了;这只是对您的代码进行修改以执行您想要的操作,甚至可以帮助您进一步理解:
for (i = 0; i < divs.length; i++)
{
(function(j)
{
setTimeout(function ()
{
divs[j].style.left = divs[j].offsetLeft + 550;
}, j * 1000); // simply multiply j by 1000
})(i); //Pass current value into self-executing anonymous function
}
编辑(解释):setTimout 接受以毫秒为单位的延迟(1/1000 秒),j
在0
和divs.length-1
之间。通过将此值乘以在操作之间延迟的毫秒数,您最终会为它提供从执行上述代码的那一刻开始等待每次执行的总毫秒数。
好的,所以你想要这样的东西... http://jsfiddle.net/92xx7u21/
Javascript:
var oDivs = document.getElementsByTagName('div');
window.doit = function(iLength, iCounter){
setTimeout(function () {
$(oDivs[iCounter]).width(($(oDivs[iCounter]).width() - 10) + "px");
iCounter++;
if (iCounter<iLength) {
doit(iLength, iCounter);
} else {
alert('done');
}
}, 1000);
};
doit(oDivs.length, 0);
基本上这是一个自调用函数,你用底线启动一次然后它会自己调用直到它达到元素的长度..它可以清理一点,但尽量保持很简单..你需要再次添加你的随机时间,因为我把它保持在每个循环 1 秒。
因为我没有您的任何其他代码,所以我使用 jQuery 完成了此操作以使其成为一个简单的示例,并且在这种情况下也只是调整了宽度。
所以,我制作了一个容器 div,在里面 div 我有一个脚本动态创建 113 个 div 的 class 名称 [=33] =].现在,一切都井井有条了,我特地把那 113 div 做得非常小,大约 5X5 像素。然后我把它们放在容器里,让它们拼出一个标题。所有 div 都在一个名为 divs 的数组中。所以 divs 是一个有 113 个元素的数组。
现在事情变得混乱了,我想让那些 div 隐藏在浏览器的不可见区域后面,我通过提供 'fragments' 绝对定位并设置它们隐藏的样式来实现这一点,例如: divs[45].style.left = -600';
,在那之后,我创建了一个脚本 运行 a for-loop 在里面 for-loop 我想要每个小元素在延迟后返回到它的位置。但是,我不得不为此使用闭包,因为在 for-loop 中插入 SetTimeout()
很奇怪。
for (i = 0; i < divs.length; i++)
{
(function(j)
{
setTimeout(function ()
{
divs[j].style.left = divs[j].offsetLeft + 550;
}, Math.floor(Math.random() * 1000));
})(i); //Pass current value into self-executing anonymous function
}
我无法理解上面的代码。我以为写Math.floor(Math.random() * 1000)
的区域是指定延迟ms的。但是,如果我输入 1000,它将立即移动所有 113 个元素。我不明白这一点,它不应该在移动到数组中的下一个元素之前等待 1 秒吗?顺便说一下,代码运行良好,最终发生的是元素随机移动,给标题带来了非常酷的效果。闭包对我来说已经够混乱了,对我来说这似乎是非常奇怪的行为。
有人能解释一下为什么会发生这种情况吗?如果我取出 Math.floor(Math.random() * 1000)
,为什么所有元素都会同时移动,而不是简单地让一个元素大约每秒移动一次。 .. *
编辑
我的问题不是关于闭包,而是关于为什么取出 Math.floor(Math.random() * 1000)
并将其替换为“1000”,导致所有元素立即移动,而不是一个一个地间隔 1000 毫秒.
所有 setTimeout 都在(几乎)同时实例化,并且因为它们都有 1 秒的延迟,所以它们都在(几乎)同时启动。
如果要按顺序添加元素,则需要递归进行。如果您使用 for
循环,那么您将 "simultaneously" 安排一堆计时器。他们会同时开始倒计时,他们都会尽快结束,互不关心。
以下是如何按顺序安排计时器的示例:
var things = [1, 2, 3];
(function next(array) {
setTimeout(function () {
var item = array[0],
remaining = array.slice(1);
console.log(item);
if (remaining.length > 0) {
next(remaining);
}
}, 1000);
}(things));
如果您正在进行大量异步工作,或者如果您想处理类似于同步任务的异步任务,请尝试 Async。它提供了一些不错的循环机制:
async.eachSeries(things, function (thing, callback) {
setTimeout(function () {
console.log(thing);
callback();
}, 1000);
}, function () {
console.log('all done');
});
根据前面的回答,我很确定你已经理解了;这只是对您的代码进行修改以执行您想要的操作,甚至可以帮助您进一步理解:
for (i = 0; i < divs.length; i++)
{
(function(j)
{
setTimeout(function ()
{
divs[j].style.left = divs[j].offsetLeft + 550;
}, j * 1000); // simply multiply j by 1000
})(i); //Pass current value into self-executing anonymous function
}
编辑(解释):setTimout 接受以毫秒为单位的延迟(1/1000 秒),j
在0
和divs.length-1
之间。通过将此值乘以在操作之间延迟的毫秒数,您最终会为它提供从执行上述代码的那一刻开始等待每次执行的总毫秒数。
好的,所以你想要这样的东西... http://jsfiddle.net/92xx7u21/
Javascript:
var oDivs = document.getElementsByTagName('div');
window.doit = function(iLength, iCounter){
setTimeout(function () {
$(oDivs[iCounter]).width(($(oDivs[iCounter]).width() - 10) + "px");
iCounter++;
if (iCounter<iLength) {
doit(iLength, iCounter);
} else {
alert('done');
}
}, 1000);
};
doit(oDivs.length, 0);
基本上这是一个自调用函数,你用底线启动一次然后它会自己调用直到它达到元素的长度..它可以清理一点,但尽量保持很简单..你需要再次添加你的随机时间,因为我把它保持在每个循环 1 秒。
因为我没有您的任何其他代码,所以我使用 jQuery 完成了此操作以使其成为一个简单的示例,并且在这种情况下也只是调整了宽度。