【问题标题】:setInterval inside a for causing function to faila 中的 setInterval 导致函数失败
【发布时间】:2012-09-14 07:24:23
【问题描述】:

我有两个功能

 function getImgStr(imgName){
        thisStr = '<img src="/_shared/img/discovery/200x100/'+imgName+'.jpg">';
        return thisStr;
    }
    function buildIt(imgSrc){
        console.log(imgSrc);
        $('#content').append('<div></div>');
        $('#content div:last').hide()
            .addClass('imgBox')
            .attr('id',imgSrc)
            .html(getImgStr(imgSrc))
            .slideDown(2000);
    }

我有一个正在循环的数组

$(function(){
        for(i=0;i<=imgList.length-1;i++){
                buildIt(imgList[i]);
        }
    });

工作正常,没有问题。

但是当我尝试包装时,这是一个 setInterval is barfs

$(function(){
        for(i=0;i<=imgList.length-1;i++){
            var loadIt = setInterval(function(){
                buildIt(imgList[i]);
            },1000);
        }
    });

当 setInterval 存在时, buildIt 中的 console.log 是未定义的,所以我假设间隔会以某种方式影响循环,但我不明白我做错了什么。有什么想法吗?

【问题讨论】:

  • 尝试用循环的内容编写另一个函数并将任何变量(包括索引i)传递给它。
  • 另外,如果您不需要,您可能不想将 setInterval 设置为变量。我知道 clearInterval 是结束间隔计时器的原因,但是在循环中覆盖该变量也可能会影响它(尚未对此进行测试)。
  • 您的 for 循环在您的 setInterval 甚至运行 sp 之前完成,它很可能将 imgList[4] 传递给您的函数。
  • setInterval 本身就是一个循环。您应该决定是要间隔多次执行代码(使用setInterval),还是立即执行(使用普通循环)。

标签: javascript jquery for-loop setinterval


【解决方案1】:

根据您的说明:如果您想每秒一个接一个地加载图像,您可以执行以下操作。你根本不需要循环。

var i = 0;
var id = setInterval(function() {
    if(i === imgList.length) {
        clearInterval(id);
    } else {
        buildIt(imgList[i++]);
    }
}, 1000)

它的作用是将i 的值初始化为0。i 的功能与for 循环中的i 完全相同。它本质上是一个索引。然后,将区间的值存储在变量id 中。通过这种方式,您可以维护对间隔的引用,以便在加载完图像后将其清除。

最后,在区间函数中检查i 是否等于图像列表中图像数量的长度。如果是,我们知道我们已经完成了所有的加载,所以我们清除了间隔。否则,我们为与i 的当前值对应的图像调用buildIt 函数,并增加i 的值。

【讨论】:

  • 也许我使用的 setInterval 错误。我在 imgList 数组中有六个图像,我希望它们一次加载一个,中间有一秒钟。
  • -1 Vivin,我不想告诉你,但你的解决方案也不起作用 - 请参阅下面我的示例中的wrong3,这是你的解决方案,例如简化。跨度>
  • @EthanBrown 我很清楚这些警告;没有什么可以对我“打破”的。 OP没有解释他想做什么。我离开了他在最初的帖子中描述的内容。他从来没有解释过他想一个接一个地加载图像,这就是我要求他澄清的原因。你没看到我回答的最后一行吗?
  • 谢谢@Vivan!就是这样!
  • +1 在我做之前,您已经明白了@Lance 想要做的事情。干得好。
【解决方案2】:

更新 fiddle

   this.buildIt= function(imgSrc){
    console.log("test"+imgSrc)
    console.log(imgSrc.length)
        };

$(function(){ 
      var imgList=[
"test1","test2","test3","test4"
]
        for(i=0;i<=imgList.length;i++){

            var loadIt = setInterval(function(){
                this.buildIt(imgList);
            },1000,imgList);
        }
    });​

【讨论】:

  • 这 (jsfiddle.net/EQMDz/1) 可能是我所寻找的最接近的。这是每个人的建议的组合。现在,如果我能弄清楚如何在 index == imgList.length 时清除Interval(),我的状态就会很好。
  • @Lance 这正是我在我的解决方案中所做的(清除index === imgList.length 时的间隔。你看过了吗?
【解决方案3】:

更新:我仍然不完全清楚 OP 试图做什么,但根据我的理解,我将通过堆上的另一个解决方案。您有 N 个图像,并且您希望每秒按顺序更新这些图像。为此,您必须将setTimeoutsetInterval 结合起来。 setTimeout 会错开图片的更新,setInterval 会导致每张图片依次更新。下面是它的外观:

function start() {
    var nImages = 5;
    for( i=0; i<nImages; i++ ) {
        (function(j){
            setTimeout( function() {
                buildIt(j);
                intervals.push(
                    setInterval( function() {
                        buildIt(j);
                    }, 1000*nImages )
                );
            }, j*1000 );
        })(i);
    }
}

function stop() {
    for( i in intervals ) {
        clearInterval( intervals[i] );
    }
}

这是一个 jsFiddle 演示:http://jsfiddle.net/FtCCs/

这是我之前的回答: ​​​ Vivin 走在正确的轨道上,但他的解决方案也行不通,因为它只是将闭包问题推到了堆栈的下方。但是,他在一方面是正确的:您的 buildIt 函数调用没有获得您期望的索引,而是所有相同的索引。你需要做的是:

$(function(){
    for(i=0;i<=imgList.length-1;i++){
        (function(j){
            var loadIt = setInterval(function(){
                buildIt(imgList[j]);
            },1000);
        })(i);
    }
});

为了清楚地说明发生了什么,请考虑以下示例:

HTML:

<div id="wrong1">Wrong:<br /></div>
<div id="wrong2">Wrong:<br /></div>
<div id="wrong3">Wrong:<br /></div>
<div id="right">Right:<br /></div>

jQuery:

// won't work:
for(var i=0;i<5;i++) {
    setTimeout( function() { $('#wrong1').append(i+'<br />'); }, 500 );
}

// won't work:
for(var i=0;i<5;i++) {
    var j = i;
    setTimeout( function() { $('#wrong2').append(j+'<br />'); }, 500 );
}

// won't work:
for(var i=0;i<5;i++) {
    setTimeout( function() { (function(j){ $('#wrong3').append(j+'<br />'); })(i) }, 500 );
}

// works!
for(var i=0;i<5;i++) {
    (function(j){
        setTimeout( function() { $('#right').append(j+'<br />'); }, 500 );
    })(i);
}

我这里设置了一个JsFiddle来演示:http://jsfiddle.net/k3RJL/1/

在所有“错误”示例中,变量 ij 是一个闭包,但当 setTimeout 中的函数执行时,该值已更改为该闭包内的最终值,所以他们都是一样的。注意wrong2 的区别:它查看的是在for 循环内定义的变量j,因此它永远不会收到i 的最终值,这就是它停在4 的原因。

【讨论】:

  • 感谢 Ethan,看来我快到了,您的示例和解释真正阐明了如何将信息传递给 setTimeout。但我仍然很困惑。最后一个是作为作品!与我有相同的结果 'for(i=0;i
  • @Ethan,你甚至不需要循环。您可以将边界检查包含在闭包内。
  • 那是因为循环实际上将它们设置为同时启动。如果你想让它们交错,你必须更聪明一点。
  • -1 @EthanBrown OP 想要一次加载一个图像。请参阅我的编辑。我不太了解您的解决方案的重点或它如何解决 OP 的问题。您只需对其进行设置,以便在一段时间后将图像一起加载。这与同时加载它们有什么不同没有等待?
  • 我现在明白了,维文。起初并不清楚。我更担心闭包的错误使用,但我也会解决他的另一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-09-24
  • 2013-06-24
  • 2015-07-09
  • 1970-01-01
  • 2021-01-27
  • 2021-07-28
  • 1970-01-01
相关资源
最近更新 更多