繁体   English   中英

令人困惑的For循环内部超时和关闭

[英]Confusing For-loop with timeout inside and closure

所以,我创建了一个容器div,在div中我有一个脚本动态创建113个div,类名为'fragment'。 现在,一切都井然有序,我专门制作了113个div非常小,大约5X5像素。 然后我把它们放在容器中,这样他们拼出一个标题。 所有的div都在一个名为div的数组中。 所以div是一个包含113个元素的数组。

现在这里的事情让人感到困惑,我想让这些div隐藏在浏览器的隐形区域后面,我通过给出'碎片'的绝对定位来实现这一点,并将它们设置为隐藏例如: divs[45].style.left = -600'; 之后,我创建了一个运行for循环的脚本,并且在for循环内部我希望每个小元素在延迟后返回到它的位置。 但是,我必须使用闭包,因为在for循环中插入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'替换它,导致所有元素一次移入,而不是一个接一个,间隔1000ms。

所有setTimeout都在(几乎)同时实例化,并且因为它们都有1秒的延迟,所以它们都在(几乎)同时启动。

如果要按顺序添加元素,则需要递归执行。 如果你使用for循环,那么你将“同时”安排一堆定时器。 他们都会在同一时间开始倒计时,他们都会尽快完成,而不顾彼此。

以下是如何按顺序安排计时器的示例:

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');
});

好的,所以你想要这样的东西...... 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做了这个,使它成为一个简单的例子,在这种情况下也只是调整宽度。

鉴于以前的答案,我很确定你理解; 这只是对您的代码进行修改以执行您想要的操作,甚至可以帮助您进一步理解:

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介于0divs.length-1 通过将此值乘以在操作之间延迟的毫秒数,您最终会给它从上一次执行代码开始等待每次执行的总毫秒数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM