Created
March 17, 2009 23:55
-
-
Save duncanbeevers/80841 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Buffer up calls to groups of functions, unwind stack when precondition is met. | |
Calls to a buffered function prior to its preconditions being met are queued | |
and are later played back to the function when the precondition is met. | |
Groups of functions can share a common call stack by sharing a precondition object, | |
which is a simple function reference. | |
For simple control over how calls are played back, provide a tag with each buffered | |
function declaration. When tags are used, buffered calls are first sorted by their | |
tag, then by their timestamp, giving you in-order, per-tag function playback. | |
var precondition = function(){ return obj.isBarrierCleared(); }, | |
obj = { | |
_barrierCleared: false, | |
_stack: [], | |
isBarrierCleared: function() { | |
return this._barrierCleared; | |
}, | |
fn1: function(i) { | |
this._stack.push('fn1:' + i); | |
}.bufferingFunction(precondition, 'tagged A'), | |
fn2: function(i) { | |
this._stack.push('fn2:' + i); | |
}.bufferingFunction(precondition, 'tagged B'), | |
clearBarrier: function() { | |
this._barrierCleared = true; | |
} | |
}; | |
obj.fn1(1); | |
obj.fn2(1); | |
obj.fn1(2); | |
obj.clearBarrier(); | |
obj.fn1(3); | |
obj._stack; | |
>> ["fn1:1", "fn1:2", "fn1:3", "fn2:1"] | |
If you need very fine control over the order in which calls are played back to the | |
original functions, you may provide a sorting function which will sort buffered calls | |
prior to playback. A sorting function should accept two call stack objects, A and B, | |
compare them, and return -1, 0, 1 depending on whether A should occur before B, A and B | |
are equivalent, or B should occur before A. | |
*/ | |
Function.prototype.bufferingFunction = function(precondition, unspoolSorter) { | |
var call_buffer = Function.preconditionBufferingGroup(precondition, unspoolSorter), | |
originalFunction = this, | |
outerFunction = function() { | |
call_buffer.push(originalFunction, arguments, this, outerFunction, unspoolSorter); | |
if (precondition(this)) { call_buffer.unwind(); } | |
}; | |
return outerFunction; | |
}; | |
Function.preconditionBufferingGroup = function(precondition, unspoolSorter) { | |
if (!this._buffering_function_groups) { this._buffering_function_groups = []; } | |
if (undefined === precondition._buffering_group_id) { | |
precondition._buffering_group_id = this._buffering_function_groups.length; | |
} | |
var buffering_group_id = precondition._buffering_group_id; | |
if (!this._buffering_function_groups[buffering_group_id]) { | |
this._buffering_function_groups[buffering_group_id] = function() { | |
var stack = []; | |
return { | |
push: function(fn, args, bind_to, outerFunction, unspoolSorter) { | |
stack.push({ | |
fn: fn, | |
outerFunction: outerFunction, | |
args: args, | |
bind_to: bind_to, | |
timestamp: new Date(), | |
tag: unspoolSorter | |
}); | |
}, | |
unwind: function() { | |
if (!stack.length) { return; } | |
var c, | |
tagAndTimestampSorter = function(a, b) { | |
var cmp = function(a, b) { | |
if (a.localeCompare && b.localeCompare) { | |
return a.localeCompare(b); | |
} | |
if (a > b) { return -1; } | |
if (a < b) { return 1; } | |
return 0; | |
}; | |
return (cmp(a.tag, b.tag) || cmp(a.timestamp, b.timestamp)); | |
}; | |
if (unspoolSorter instanceof Function) { | |
stack.sort(unspoolSorter); | |
} else if (unspoolSorter) { | |
stack.sort(tagAndTimestampSorter); | |
}; | |
while (c = stack.shift()) { | |
var fn = c.fn, | |
args = c.args, | |
bind_to = c.bind_to; | |
fn.apply(bind_to, args); | |
} | |
} | |
}; | |
}(); | |
}; | |
return this._buffering_function_groups[buffering_group_id]; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment