setTimeout存在问题

时间:2010-10-26 13:52:45

标签: javascript animation settimeout

我最近问了一个关于同一个函数的问题,它解决了我的探针问题,并指导我进行了一个tutoraial,因为我正在使用while循环,这意味着我的函数没有动画,只是冻结然后调整大小。这种新的方式,使用setTimeout应该工作。唯一的问题是它只是抓住新的尺寸而不是动画。根据萤火虫没有错误。这是我目前管理动画的代码部分。

// Resize in timeframe
// Work out distance
var widthdiff = width - parseInt(element.style.width);
var heightdiff = height - parseInt(element.style.height);

// Work out how miliseconds per step (100 in total)
var steptime = timeframe / 100;

// Work out how many pixels it needs to move each step
var widthpps = widthdiff / 100; // ERROR?
var heightpps = heightdiff / 100;

// Set up original sizes
var origwidth = parseInt(element.style.width);
var origheight = parseInt(element.style.height);

// Loop through all 100 steps setting a time out resize each time
var timers = [];
for(var i = 0; i < 100; i++)
{
    timers[i] = setTimeout(function() { // ERROR?
        element.style.width = origwidth + (widthpps * i) + 'px';
        element.style.height = origheight + (heightpps * i) + 'px';
    }, i * steptime);
}

争论被传递得很好,我已经测试了所有这些,我曾经让它动画一次,只是错了。所以我的问题将接近名为ERROR的评论?我相信。谢谢你的帮助。

3 个答案:

答案 0 :(得分:5)

问题是变量“i”将被所有超时函数共享

您可以编写单独的函数来构建超时函数,或者可以将函数包装在内:

timers[i] = setTimeout((function(privateEye) {
    return function() { 
      element.style.width = origwidth + (widthpps * privateEye) + 'px';
      element.style.height = origheight + (heightpps * privateEye) + 'px';
    })(i), i * steptime);

当我说“i”将被“共享”时,我的意思是你在循环中构建的每个函数都将正确引用该循环变量。但是那个变量发生了什么?它在循环的每次迭代中都在变化。重要的是要理解这些函数将引用真实“i”变量,而不是冻结副本。通过使用 second 函数,如上所述,您可以在循环中使用“i”的副本

答案 1 :(得分:1)

我还没有完全审核过代码,但是有一个错误符合您的症状:

timers[i] = setTimeout(function() { // ERROR?
    element.style.width = origwidth + (widthpps * i) + 'px';    // <== error
    element.style.height = origheight + (heightpps * i) + 'px'; // <== error
}, i * steptime);

问题是这些函数会收到实时引用i,而不是它的循环迭代值的副本。所以他们都看到i的最后一个值。

这很容易解决:

timers[i] = setTimeout(makeStepFunction(i), i * steptime);

// Anywhere in the surrounding function, not in the loop:
function makeStepFunction(step) {
    return function() {
        element.style.width = origwidth + (widthpps * step) + 'px';
        element.style.height = origheight + (heightpps * step) + 'px';
    };
}

现在setTimeout将调用的函数正在使用传递给makeStepFunction的参数,而不是i

可以在没有命名函数的情况下执行此操作,但它会非常快速地混淆:

timers[i] = setTimeout((function(step) {
    return function() {
        element.style.width = origwidth + (widthpps * step) + 'px';
        element.style.height = origheight + (heightpps * step) + 'px';
    };
})(i), i * steptime);

这一切都与闭包(“关闭”数据的功能)如何在JavaScript中工作有关。它们真的很强大,但一旦你知道它们是如何工作的,它们并不复杂。 FWIW,我的博客文章 Closures are not complicated 可能会有所帮助。一旦你知道它们是如何工作的,它们就会失去神秘感(并且变得更加有用)。

答案 2 :(得分:1)

另一种解决方案是使用setInterval并使该方法使用在每次传递时更新的全局i以及取消setInterval的截止值。

var i = 0;
var interval = setInterval(
    function() {
        element.style.width = origwidth + (widthpps * i) + 'px';
        element.style.height = origheight + (heightpps * i) + 'px';
        i++;
        if(i==100)
             clearInterval(interval);  //Stops executing
    }, stepTime);

找到关于setTimeout和setInterval如何工作的一些解释,以查看哪个最适合您的目的。 http://ejohn.org/blog/how-javascript-timers-work/