jquery icon indicating copy to clipboard operation
jquery copied to clipboard

Use RAF's timestamp for smoother animations

Open joliss opened this issue 9 years ago • 18 comments

jQuery 3.0.0-rc1 uses requestAnimationFrame, resulting in significantly smoother animations compared to before. However, its tweening logic uses Date.now() instead of the RAF timestamp argument. As a result, the animation is still slightly choppy.

Before you switch to using timestamp, I should point out that the Velocity.js library opts not to use timestamp (velocity.js:3366):

/* We ignore RAF's high resolution timestamp since it can be significantly offset
   when the browser is
   under high stress; we opt for choppiness over allowing the browser to drop huge
   chunks of frames. */
var timeCurrent = (new Date).getTime();

I don't know if this is actually still an issue in modern browsers. @julianshapiro originally wrote this code in 2014 -- perhaps he can chime in with some details.

I created a test case to demonstrate choppiness resulting from not using timestamp: https://codepen.io/joliss/pen/wWKGeV/ (The test case uses Velocity.js, but I believe it's the same for jQuery.)

My hope is that you can use this test case as a debugging aid, and as a motivating example to convince browser vendors to get any remaining timestamp issues resolved.

Running the CodePen, we see that there is some slight choppiness with the jQuery's getTime implementation:

a pen by jo liss jtbyc

Using the RAF timestamp argument instead, the animation feels smoother, and the graph is perfectly smooth as well:

a pen by jo liss her4j

I thought that perhaps using the microsecond-resolution performance.now() function would improve smoothness, but it doesn't seem to help much:

a pen by jo liss hft9a

joliss avatar Jun 06 '16 19:06 joliss

A great analysis, thanks a lot! I'm surprised that using performance.now() gives worse results than using the timestamp since it's based on the same timer.

I made a quick patch for jQuery 3.0.0-rc1 that made it use the rAF timestamp: https://gist.github.com/mgol/59155e734d86095f58d505824f7503c2 and added a button for it in your test case: http://codepen.io/mgol/pen/VjvjdL

The graph looks similar to the Velocity using timestamp one.

Note that I'm seeing the performance difference in Chrome 51 but I don't see any gain in Safari (9.1 & TP) and Firefox; Safari mostly looks like your "Velocity plus performance.now" test case in all cases (including the getTime one in which it's better than Chrome), Firefox looks terrible in all cases. I'm not sure if doing sth like that just for Chrome is worth it... :/

EDIT: In Edge 13 all cases look the same, worse than in Safari but way better than in Firefox.

mgol avatar Jun 06 '16 21:06 mgol

Re Firefox: the terrible graphs that I'm seeing are there only if I use the integrated graphics card in my MacBook. i.e. Intel Iris Pro 1536 MB. If I switch to the dedicated AMD Radeon R9 M370X 2048 MB, it gets closer to Safari. Perhaps Firefox has problems with hardware acceleration for Intel GPUs.

mgol avatar Jun 06 '16 22:06 mgol

I've always found that dropping a huge chunk of frames upfront is more visually jarring than an FPS hit. In real world (low-stress) animation scenarios, the FPS hit isn't that noticeable — if at all.

julianshapiro avatar Jun 06 '16 22:06 julianshapiro

@mgol Good point. I created an issue on the Firefox bug tracker: https://bugzilla.mozilla.org/show_bug.cgi?id=1278408 Let's see what they say, and if necessary we can create issues on Edge and Safari too.

@julianshapiro I agree dropping chunks of frames is really bad. Is this still happening though? (Or to be more precise, is it worse for timestamp compared to Date.now()?) Plotting timestamp values with a no-op requestAnimationFrame, I don't see any initial framedrops: https://codepen.io/joliss/pen/ZObOPm

joliss avatar Jun 06 '16 22:06 joliss

Very cool. Thanks for this.

timmywil avatar Jun 07 '16 15:06 timmywil

I also updated the bug with a reference to an older bug on which I added @bzbarsky to take a deeper look.

digitarald avatar Jun 07 '16 16:06 digitarald

Nice test!

Judging by the discussion in mozilla thread we still can't use it right? After it will be fixed (fingers crossed), we still should look at older/other browsers that we support?

markelog avatar Jun 08 '16 02:06 markelog

On Firefox 46 with Windows 10 it looks as smooth as Chrome. As long as we don't make things much worse on Firefox by changing to the rAF timestamp is there anything to stop us from changing it now? To @markelog's point we would also need to ensure it doesn't degrade too much for browsers like Android or IE9.

dmethvin avatar Jun 08 '16 08:06 dmethvin

@dmethvin My quick patch made jQuery.fx.tick accept a timestamp parameter so that'd slightly change the API; to avoid that we'd need a wrapper function which might increase the code size a little.

I just don't see much gain in using the timestamp until it improves the situation only in Chrome. Maybe as a way of preparing for the future? I can prepare a PR to discuss the details further.

mgol avatar Jun 08 '16 09:06 mgol

Ah, you said it's as smooth as Chrome for you in Firefox on Windows 10. Do you mean it looks like the same graph as the second one from the original @joliss post, completely smooth? That'd change the situation. :)

mgol avatar Jun 08 '16 09:06 mgol

Yeah, here are my Firefox results, very smooth: capture

dmethvin avatar Jun 08 '16 09:06 dmethvin

In here @mgol points out that timestamp dependant on graphics card (@dmethvin your card might just be in "good" category), is it not case? The same story could be with other browsers?

This https://bugzilla.mozilla.org/show_bug.cgi?id=1278408#c10 is also disturbing

markelog avatar Jun 08 '16 09:06 markelog

Also, if we can do this and it is not the issue, why those tickets are open?

markelog avatar Jun 08 '16 09:06 markelog

In here @mgol points out that timestamp dependant on graphics card (@dmethvin your card might just be in "good" category), is it not case?

Possible. The current data points to the thesis that it's never worse when using the timestamp than when not using it and sometimes it's better.

mgol avatar Jun 08 '16 12:06 mgol

PR: #3151. Please review.

mgol avatar Jun 08 '16 12:06 mgol

CC’ing Mozilla folks: @miketaylr @digitarald @bzbarsky @annevk @kentuckyfriedtakahe @cyberdees

mgol avatar Jun 22 '16 11:06 mgol

Pushing to at least 3.3.0 as Chrome apparently has a bug that makes timestamps arrive to our step function not always in ascending order. See https://github.com/jquery/jquery/pull/3151#issuecomment-285347910 for more details.

mgol avatar Mar 15 '17 16:03 mgol

This requires more investigation, with issues around out-of-order scheduling in Chrome that I've experienced as well as recent timer throttling due to Spectre. Postponing to 4.0.0.

mgol avatar Oct 03 '18 11:10 mgol