【问题标题】:A problem with setTimeout设置超时的问题
【发布时间】:2010-10-26 13:52:44
【问题描述】:

我最近问了一个关于同一个函数的问题,它解决了我的问题并引导我学习教程,因为我使用了一个 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 的 cmets?我相信。感谢您的帮助。

【问题讨论】:

    标签: javascript animation settimeout


    【解决方案1】:

    问题是变量“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”将是“共享”时,我的意思是您在循环中构建的每个函数都将正确引用该循环变量。但是那个变量发生了什么?它在循环的每次迭代中都会发生变化。重要的是要了解函数将引用 real "i" 变量,而不是冻结副本。通过使用 second 函数,就像我在上面所做的那样,您制作了循环中使用的“i”的 copy

    【讨论】:

    • 知道了!非常感谢,这是我写过的最有问题的剧本。不过现在可以完美运行。我什至可能会尝试放松,这会产生一些我想象的有趣错误
    • 如果您从未遇到过任何编码问题,那么您将永远不会发现对代码工作方式的新见解。或者,正如尼采所说,“杀不死我们的会让我们更强大。”
    • 好吧,如果您真的想要它,可以在该链接中找到该脚本。它由 s.size('css selector of element', width, height, timeframe in milliseconds) 运行; github.com/Wolfy87/Spark/raw/master/spark.js
    【解决方案2】:

    我还没有完全审核代码,但是这里有一个与您的症状相符的错误:

    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 可能会有所帮助。一旦您了解了它们的工作原理,它们就会失去神秘感(变得更加有用)。

    【讨论】:

    • 您的意思是“它们很复杂”吗?
    • @Pointy:不。事实上,链接是我的博文“闭包并不复杂。” :-)
    • 哦,好酷。我认为该评论旨在支持“令人困惑”的事情。我当然同意,我最希望的主要是关键字“function”要短得多:-)
    • @Pointy:重读一遍,我觉得很容易误读,所以我改写了。
    【解决方案3】:

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

    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/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-23
      • 2010-10-22
      • 2011-04-27
      • 2016-01-06
      • 2014-09-30
      • 2014-01-30
      相关资源
      最近更新 更多