Проблема с setTimeout - PullRequest
       13

Проблема с setTimeout

1 голос
/ 26 октября 2010

Недавно я задал вопрос о той же функции, которая решила мой пробелем и направила меня к туторалу, потому что я использовал цикл while, это означало, что моя функция не анимировалась, просто зависала и изменяла размеры.Этот новый способ, используя setTimeout, должен работать.Единственное, что он просто привязывается к новому размеру, а не оживляет его.Там нет ошибок в соответствии с firebug.Вот мой текущий раздел кода, который управляет анимацией.

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

Аргументы передаются нормально, я все это проверил, и у меня была анимация один раз, просто неправильно.Так что моя проблема будет лежать рядом с комментариями под названием ОШИБКА?Я верю.Спасибо за любую помощь.

Ответы [ 3 ]

5 голосов
/ 26 октября 2010

Проблема в том, что переменная "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", а не на замороженную копию.Используя секундную функцию, как я делал выше, вы создаете копию «i», используемого в цикле.

1 голос
/ 26 октября 2010

Другое решение состоит в том, чтобы использовать 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/

1 голос
/ 26 октября 2010

Я не полностью проверил код, но есть ошибка, которая соответствует вашему симптому:

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, мое сообщение в блоге Закрытия не сложны может быть полезным. Когда вы знаете, как они работают, они теряют свою тайну (и становятся еще более полезными).

...