Angular.js: Add option to run $timeout as an requestAnimationFrame callback

Created on 4 Oct 2013  路  14Comments  路  Source: angular/angular.js

I think it's been claimed by a bunch of smart folks that you should avoid using setTimeout at all costs and replace it with requestAnimationFrame.

Even if you know that you want to run some code in 1000ms it's still smarter to schedule the code with setTimeout but then call requestAnimationFrame to actually do the work. At least if your work is rendering related.

To let code speak, this:

setTimeout(function(){
    requestAnimationFrame(function(){
        doWork();
    });
},1000);

So in terms of Angular this could look like this:

//I would advise changing the last parameter to be an option object 
//because currently it's used for invokeApply
$timeout(doWork, 1000, { invokeApply: false, requestAnimationFrame: true});

I wonder if you guys agree that it makes sense to have it baked into the framework. After all, it's just a couple of lines of code for the framework that makes life easier for the developer because it takes care of $apply and returning you a promise etc.

If you think it's a good idea, I'll craft a PR for it.

investigation

Most helpful comment

Why not expose (and document) $$RAFProvider?

There are legitimate cases when we need to use a RAF ourselves for things which ng-animate isn't suitable for...

All 14 comments

I think @matsko is on this?

Yeah I have it in a commit offline. In the process of doing a huge refactoring on $animate to make this work better. I'll close this issue once I have the commit pushed up which should be in the next couple days or so.

Ah, great to hear!

@cburgdorf looks like we don't need this feature. The way that ngAnimate works now is it uses a global timeout (just one) to manage all concurrent animations. So if you have a repeater with 1000 items then everything will be grouped together. I tried doing this with requestAnimationFrame() but the cancellation wasn't fast enough to group everything together. Also requestAnimationFrame() isn't supported by android devices and overall the purpose of the feature is to make incremental JavaScript animations more performant. Which isn't what we're trying to do with CSS3 transitions. So looks like we won't be using this for now.

Well, not for ngAnimate but I thought it's quite useful for angular in general. Don't you think?

Agreed. It would be a handy shortcut for those of us using JS to do things that can cause jank.

Going to see if this works with our new setup on 1.2.x

Good news. This works great with the latest ngAnimate code. And it fixes a bunch of flicker-related bugs.

This will surface in 1.2.9.

@matsko great work!

awesome thanks

@c0bra there is a hidden service for this called $$animateReflow (just don't tell anyone ;)).

Great to see this made it into core. I think $requestAnimationFrame or $rAF would have been a better name though for three reasons:

  • it follows the rule of _least astonishment_ for the developer
  • it's more symmetric to things like $timeout and $interval
  • the word _reflow_ might be a bit misleading as a function scheduled with the service doesn't necessarily triggers a reflow

There's also a more robust polyfill which was initially created by an Opera guy. Paul Irish blogged about it:

http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

Agreeing with @cburgdorf

Why not expose (and document) $$RAFProvider?

There are legitimate cases when we need to use a RAF ourselves for things which ng-animate isn't suitable for...

Was this page helpful?
0 / 5 - 0 ratings