📜 ⬆️ ⬇️

Understanding jQuery animation

image Hello. Today, I wanted to write a topic that the animation mechanism in jQuery is not effective, creates a bunch of timers, each of which works separately, which leads to excessively frequent redrawing of content and greatly slows down the browser, and wanted to describe some of the techniques for writing "correct animation." During the preparation of the examples, I realized that I was wrong . The jQuery animation engine is really not effective, it creates a lot of problems, but the reasons for these problems are not at all in creating a large number of timers, but in something completely different, and it seems I have achieved remarkable results in eliminating these problems.

So, we will talk about the out of sync movement of animated objects, even if they were all animated by a single call animate.
Let's look at a small example of simultaneously animating a large number of objects:
< div class ="container" >
< div class ="animate" >
</ div >
</ div >
< script type ="text/javascript" >
$( function (){
for ( var i = 0; i < 8; i++) {
$( '.animate' ).clone().appendTo( '.container' );
}
$( '.animate' ).animate({
left: 800
}, 500);
});
</ script >

* This source code was highlighted with Source Code Highlighter .

In theory, all these objects should move synchronously. In practice, we get the following picture:
image

It is clear that the test is synthetic, in the real page it would be necessary to move the parent of all these objects, but the result is on the face, the animation, even in the aisles of one call, animate starts and ends at different times. Here it would be logical to assume that for each object a separate timer is created that serves it. But as I said above, this assumption is not true. Having rummaged in the source code a little, it became clear to me that only one timer is created for animating elements inside a single animate call. Moreover, for any animation made on the page using jQuery, only one timer is used, which is deleted after the completion of the last animation on the page and is recreated when you need to animate something.
')
Nevertheless, the reason for desynchronization is close to the multiplicity of timers, it lies in the fact that for each element the start time of its animation is considered to be independent. If there are many elements, it can take a long time between the time points for the first and the last element. And this time will be the greater, the slower the browser javascript engine, as we see in the screenshot - the desync value of the opera is 110 pixels (1: 2 screenshot), the chrome has 74 pixels, and the other, very popular, sync browser more than the width of the test race, eight hundred pixels.

In addition to the discrepancy between the animation of different objects, there may be a discrepancy in the animation of different properties of the same object for the same reasons. This can spoil, for example, the synchronous change of padding and width, which should remain equal in sum. In a real situation, the edge of the object will be jumping.

And now the most important thing. Considering that there is only one timer, correcting the start time of the animation is not difficult and in a couple of minutes the necessary corrections were made to solve these problems. The fixes are that the start time of the animation for all elements is counted once when entering the animate function. I even went further, added an additional startTime parameter to the options of the animate function, which can take a custom value for the start time of the animation. This allows you to synchronize any number of calls to the animate function.

In addition to synchronization, you can use the initial time value for a few more interesting pieces:
1) Set the start time of the animation in the past and start the animation from the middle. This is convenient because you do not have to do a separate ising function (easing) for the half animation.
2) Set the start time in the future, letting the slow browser engines (hello, IE!) Chew all the objects. Here, however, the Ising function is needed, which leads to negative time offsets to the zero coordinate. standard linear and swing do not possess such properties.
3) Make animation in several passes or endless animation, setting the start time of the animation in the future. For this, an Ising function will be needed that can correctly handle a negative time offset. Due to the fact that the standard Ising swing function is built on Math.cos, it satisfies this requirement.

Note, for those who do not know, the Ising functions (easing, in Russian, probably this is easing), these are functions that take values ​​from 0 to 1, where zero is the start time, 1 is the end time of the animation, and return values ​​are also from 0 to 1, where 0 is the initial value of the property being changed, and 1 is the final one. In the general case, the values ​​of the properties may lie outside the limits of 0 and 1, well, with my patch, the time may also be less than zero.

The changes I made to the code

The time of the current step was calculated in the jQuery.fx.step function as follows:
var t = now();
I added another time parameter to the function and changed the time definition to:
var t = time || now();

In the jQuery.fx.custom function, I had to add another startTime parameter and calculate the animation start time in a similar way with the previous function:
this .startTime = startTime || now();

In addition, inside that very single setInterval, a time receipt was added:
var time = now();
and the subsequent transfer of this time in the function from the array, jQuery.timers [], which contains the functions jQuery.fx.step.

In the animate function, the optall object was added with the startTime parameter:
optall = jQuery.extend({startTime: now()}, optall)

Frankly speaking, the correction is personally very necessary for me, if I do not find any problems, I will use it at least in my projects. But what worries me is that the fix is ​​so simple, but the jQuery developers have not done it, although they have done a lot more preparatory work in transferring all the animation to one timer. Maybe this is the logic and I do not see something? Who else thinks, is it worth trying to push my changes into the framework?

Corrected jQuery version

upd. Actually, I found the main ambush of this method, it manifests itself when using queues. But everything is not too hopeless, I think I can get around this. As soon as I am sure that my decision (or the impossibility to implement it :)) will fail, I will contact the author of jQuery.

PS And yesterday I ran into non-working transparency in Opera 9.2 and the latest versions of jQuery. Description of the problem and a temporary solution .

Source: https://habr.com/ru/post/72022/


All Articles