6 votes

Comment jquery exécute-t-il systématiquement les fonctions d'animation en temps (presque) exact ?

J'ai essayé d'écrire ma propre fonction d'animation pour animer le comptage vers le haut et vers le bas d'un nombre en utilisant des boucles et la fonction setInterval fonction. Dans Chrome, elle semble fonctionner très bien, mais dans Firefox, elle semble lente et prend beaucoup plus de temps que le temps d'exécution prescrit.

Je suppose que la différence réside dans la capacité des deux navigateurs à exécuter Javascript rapidement, mais après avoir rencontré ce problème, j'étais plus curieux qu'autre chose de savoir comment jQuery est capable d'être si cohérent sur le timing, puisqu'il n'utilise apparemment pas le processus que je pensais.

Edit : Voici mon code puisqu'il a été demandé :

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 ) && 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';
}
}

2voto

Marshall Points 2498

Je ne vois rien dans votre code qui vérifie les différences de temps. Dans la plupart des bibliothèques (jQuery, MooTools, etc.), les animations s'ajustent en fonction du temps.

jQuery utilise une méthode step qui est utilisé pour déterminer la valeur suivante pour un effet. Pour voir cette fonction, ouvrez la version de développement (non compressée) de jQuery et recherchez jQuery.fx.prototype . Ce bloc de code contient le step méthode.

Disons que vous voulez dire à un élément de se déplacer d'une position à une autre. Il semble que votre code va itérer jusqu'à ce qu'il soit complet avec un nombre fixe d'animations. Vous êtes donc strict sur le nombre d'itérations plutôt que sur le temps. Les navigateurs sont souvent en retard. Quelqu'un pourrait faire tourner toutes sortes de cochonneries sur sa machine, ce qui ralentirait votre exécution. L'exécution totale de votre animation sera alors plus longue que prévu et l'animation elle-même sera "saccadée".

Donc, ce que vous devriez faire à la place, c'est être strict avec le temps, et ne pas essayer d'imposer des étapes régulières. Chaque fois que vous faites un pas dans l'animation, vous devez prendre en compte le moment où l'animation a commencé, le temps total dont dispose l'animation pour se terminer et le temps écoulé. Cela vous permet de savoir où l'animation doit se situer. Ainsi, si vous voulez déplacer un élément (linéairement) de la position 100 à 200 en 10 secondes, et que nous en sommes à 7,5 secondes, vous savez que la position doit être 175. Ensuite, une fois que le temps est égal ou supérieur aux 10 secondes, vous le réglez sur 200 et vous arrêtez la boucle.

Le code jQuery sera un peu difficile à lire en raison des effets d'assouplissement qu'il utilise et de tous les crochets internes et callbacks. Mais l'idée est assez simple.

1voto

RobG Points 41170

La réponse de Marshall fonctionne lorsque vous souhaitez qu'une animation s'exécute dans un laps de temps déterminé. Une autre exigence est de faire en sorte que quelque chose se déroule à un moment précis, comme le tic-tac d'une horloge. Pour cela, vous utilisez setTimeout et à chaque exécution de la fonction, calculez le temps restant jusqu'au prochain "tick" et appelez setTimeout avec cet intervalle (ou un intervalle un peu plus long dans le cas d'une horloge pour s'assurer que la prochaine mise à jour est juste après le prochain tic-tac complet).

En utilisant des appels séquentiels à setTimeout vous pouvez compenser la dérive qui est associée à setInterval .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X