Skip to content

Instantly share code, notes, and snippets.

@timhall
Created November 15, 2012 13:17
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save timhall/4078614 to your computer and use it in GitHub Desktop.
Save timhall/4078614 to your computer and use it in GitHub Desktop.
Updated requestAnimationFrame polyfill that uses new high-resolution timestamp
// Updated requestAnimationFrame polyfill that uses new high-resolution timestamp
//
// References:
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// https://gist.github.com/1579671
// http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
//
// Note: this is my initial stab at it, *requires additional testing*
(function () {
var lastTime = 0,
vendors = ['ms', 'moz', 'webkit', 'o'],
// Feature check for performance (high-resolution timers)
hasPerformance = !!(window.performance && window.performance.now);
for(var x = 0, max = vendors.length; x < max && !window.requestAnimationFrame; x += 1) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
// Add new wrapper for browsers that don't have performance
if (!hasPerformance) {
// Store reference to existing rAF and initial startTime
var rAF = window.requestAnimationFrame,
startTime = +new Date;
// Override window rAF to include wrapped callback
window.requestAnimationFrame = function (callback, element) {
// Wrap the given callback to pass in performance timestamp
var wrapped = function (timestamp) {
// Get performance-style timestamp
var performanceTimestamp = (timestamp < 1e12) ? timestamp : timestamp - startTime;
return callback(performanceTimestamp);
};
// Call original rAF with wrapped callback
rAF(wrapped, element);
}
}
})();
@jalbam
Copy link

jalbam commented Apr 25, 2013

Hello,

As far as I can see, this improves the time precission of the paramter sent to the callback function (for example, gameLoop function). Right?

Have you already tested it properly?

Cheers,
Joan

@pyrsmk
Copy link

pyrsmk commented Mar 15, 2014

Then, have you tested it? ;)

@jalbam
Copy link

jalbam commented Jul 21, 2019

Hello,

Sorry, I forgot to answer. I did not test this one but I tested Paul Irish's one.

I just adapted Paul Irish's polyfill to work with high resolution timing automatically (when possible) and improved the performance a little bit.

It can work with the following window.performance.now polyfill: https://gist.github.com/jalbam/cc805ac3cfe14004ecdf323159ecf40e

Here it is:

'use strict';

// requestAnimationFrame polyfill by Erik Möller.
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavic, Darius Bacon and Joan Alba Maldonado.
// Adapted from https://gist.github.com/paulirish/1579671 which derived from
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// Added high resolution timing. This window.performance.now() polyfill can be used: https://gist.github.com/jalbam/cc805ac3cfe14004ecdf323159ecf40e
// MIT license
// Gist: https://gist.github.com/jalbam/5fe05443270fa6d8136238ec72accbc0
(function() {
	var vendors = ['webkit', 'moz', 'ms', 'o'], vp = null;
	for (var x = 0; x < vendors.length && !window.requestAnimationFrame && !window.cancelAnimationFrame; x++)
	{
		vp = vendors[x];
		window.requestAnimationFrame = window.requestAnimationFrame || window[vp + 'RequestAnimationFrame'];
		window.cancelAnimationFrame = window.cancelAnimationFrame || window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame'];
	}
	if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) //iOS6 is buggy.
	{
		var lastTime = 0;
		window.requestAnimationFrame = function(callback, element)
		{
			var now = window.performance.now();
			var nextTime = Math.max(lastTime + 16, now);
			return setTimeout(function() { callback(lastTime = nextTime); }, nextTime - now);
		};
		window.cancelAnimationFrame = clearTimeout;
	}
}());

You can found it in this gist: https://gist.github.com/jalbam/5fe05443270fa6d8136238ec72accbc0

Any comments are welcome. Thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment