Как jquery последовательно выполняет функции анимации в (почти) точное время?

#javascript #jquery #animation #loops

#javascript #jquery ( jquery ) #Анимация #петли

Вопрос:

Я попытался написать свою собственную анимационную функцию, чтобы анимировать подсчет вверх и вниз числа, используя циклы и setInterval функцию. В Chrome он, кажется, работает очень хорошо, но в Firefox он кажется запаздывающим и занимает гораздо больше времени, чем предписанное требуемое время завершения.

Я предполагаю, что разница заключается в способности двух браузеров быстро выполнять Javascript, но после того, как я столкнулся с этой проблемой, мне было больше всего любопытно, как jQuery может быть настолько последовательным в выборе времени, поскольку он, по-видимому, не использует процесс, который я ожидал.

Редактировать: Вот мой код, поскольку он был запрошен:

 function tallyPrices(){

var current_total = parseFloat( $('.budget span').text() );
var new_total = 0;  
var animation_options = {
    iterationTime : 10,
    totalTime : 500
}

$('#chosen-items li').each( function(){
    if( $(this).attr('data_price') !== 'n/a' ){
        new_total  = parseFloat( $(this).attr('data_price') );
    }
});

animation_options.difference = current_total - new_total;
animation_options.delta = Math.round( Math.abs( animation_options.difference / ( animation_options.totalTime / animation_options.iterationTime ) ) * 100 ) / 100;

var timesIterated = 0;
var limit = parseFloat( $('.budget span').attr('data_high') );

var animation = setInterval( function(){
    timesIterated = priceAnimate( timesIterated, animation_options, $('.budget span'), limit);

    if(timesIterated === 'done'){
        clearInterval(animation);
        $('.budget span').text( parseFloat( Math.round( new_total * 100 ) / 100 ).toFixed(2) );
    }
}, animation_options.iterationTime );
}

function priceAnimate( count, options, el, limit ){
if( count < ( options.totalTime / options.iterationTime ) amp;amp; options.difference !== 0){
    var current = parseFloat( el.text() );
    current = Math.round( current * 100 ) / 100;

    if( options.difference < 0 ){
        el.text( parseFloat( Math.round( (current   options.delta) * 100 ) / 100 ).toFixed(2) );
    } else if( options.difference > 0 ){
        el.text( parseFloat( Math.round( (current - options.delta) * 100 ) / 100 ).toFixed(2) );
    }

    if( parseFloat( el.text() ) > limit ){
        el.parent().addClass('over');
    } else {
        el.parent().removeClass('over');
    }

    count  ;

    return count; 
} else {
    return 'done';
}
}
 

Комментарии:

1. Широкий, но очень интересный вопрос. ( 1)

2. Я бы сказал, что вы должны видеть примерно одинаковую производительность в каждом из этих браузеров для простых анимаций (если я чего-то не упускаю). Не могли бы вы показать нам свой код?

3. setInterval не обязательно должен срабатывать, когда вы ему прикажете, хотя он старается изо всех сил. Я считаю, что jQuery использует процентную базу текущего времени

4. Отредактировано для добавления кода

Ответ №1:

Я не вижу ничего в вашем коде, проверяющем разницу во времени. В большинстве библиотек (jQuery, MooTools и т. Д.) Анимация настраивается в зависимости от времени.

jQuery использует метод step , который используется для определения следующего значения эффекта. Чтобы посмотреть на эту функцию, откройте разработанную (несжатую) версию jQuery и выполните поиск jQuery.fx.prototype . Этот блок кода содержит step метод.

Допустим, вы хотите указать элементу перейти из одной позиции в другую. Похоже, что ваш код будет повторяться до тех пор, пока не будет завершено фиксированное количество анимаций. Таким образом, вы строго относитесь к количеству итераций, а не ко времени. Браузеры часто лагают. Кто-то может запускать на своей машине всевозможный мусор, что замедлит вашу работу. И тогда общее выполнение вашей анимации будет дольше, чем предполагалось, а сама анимация будет «отрывистой».

Итак, что вам следует сделать вместо этого, так это быть строгим во времени и не пытаться применять равномерные шаги. Каждый раз, когда вы «шагаете» по анимации, вы должны учитывать время начала анимации, общее время, необходимое для завершения анимации, и сколько времени прошло. С его помощью вы можете определить, где должна быть анимация. Итак, если вы хотите переместить элемент (линейно) из позиции 100 в позицию 200 за 10 секунд, а у нас 7,5 секунды, вы знаете, что позиция должна быть 175. Затем, как только время достигнет или превысит завершенные 10 секунд, вы устанавливаете его на 200 и прерываете цикл.

Код jQuery будет немного сложно прочитать из-за используемых им эффектов смягчения, а также всех внутренних перехватов и обратных вызовов. Но идея довольно прямолинейна.

Комментарии:

1. Итак, позиция анимации является компонентом ее времени, когда она снова повторяется в цикле. В этом больше смысла. Я постараюсь переписать это заново. Спасибо!

Ответ №2:

Ответ Маршалла работает там, где вы хотите, чтобы анимация выполнялась в течение определенного промежутка времени. Еще одно требование заключается в том, чтобы что-то запускалось в точное время, например, по тиканью часов. Для этого вы используете setTimeout и при каждом запуске функции вычисляете время до следующего «тика» и вызываете setTimeout с этим интервалом (или немного более длинным интервалом в случае часов, чтобы убедиться, что следующее обновление происходит сразу после следующего целого тика).

Используя последовательные вызовы setTimeout, вы можете компенсировать смещение, связанное с setInterval .