Create a gist now

Instantly share code, notes, and snippets.

@pstjvn /2phaseraf.js
Last active Aug 29, 2015

What would you like to do?
2 phase RAF
(function(global) {
var tasks = [[], []];
var doubleBufferIndex = 0;
var requestFrame = false;
var taskId = 0;
var running = false;
function requestAnimationFrame_() {
if (requestFrame) return;
requestFrame = true;
global.requestAnimationFrame(runTasks);
}
/// The actual function that will be called on each raf.
/// @param {!number} hrts The high-resolution timestamp from RAF
function runTasks(hrts) {
running = true;
requestFrame = false;
var taskArray = tasks[doubleBufferIndex];
var taskLength = taskArray.length;
// During the runTask call, if there are recursive call to queue up more takas for the
// next frame double buffering is used to avoid scheduling in the same list
// and potentially run the task twice in a single run.
doubleBufferIndex = (doubleBufferIndex + 1) % 2;
var task;
// Run the measure phase
for (var i = 0; i < taskLength; i++) {
task = taskArray[i];
task.isScheduled = false;
// Check if defined, specs might define only one of the two tasks.
if (task.measureTask) {
task.measureTask.call(task.context, hrts, task.state);
}
}
// Run the mutate phase
for (var i = 0; i < taskLength; i++) {
task = taskArray[i];
task.isScheduled = false;
if (task.mutateTask) {
task.mutateTask.call(task.context, hrts, task.state);
}
}
// Avoid re-creating the array, instead tell the engine to consider the
// allready allocated memory as zeor length list. This will keep the allocation
// and will only allocate more mem if you ever put more items in it.
taskArray.length = 0;
running = false;
}
/// Actual exported method.
/// @param {{measure: function(!number, !Object), mutate: function(!number, !Object)}} specs
/// @param {Object=} context
global.createTask = function(specs, context) {
var id = taskId++;
var taskSet = {
id: id,
measureTask: specs.measure,
mutateTask: specs.mutate,
context: context
state: {},
isScheduled: false
};
// Return a function that can be called whenever event triggers the raf.
return function() {
if (!context) {
taskSet.context = this;
}
if (!taskSet.isScheduled) {
taskSet.isScheduled = true;
var taskArray = tasks[doubleBufferIndex];
taskArray.push(taskSet);
}
requestAnimationFrame_();
}
}
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment