Files
DiceCloud/rpg-docs/lib/memoize/memoize.js
2015-06-29 09:41:01 +02:00

61 lines
1.8 KiB
JavaScript

Tracker.memoize = function(func, hasher){
var memoize = function(key) {
var cache = memoize.cache;
var address = "" + (hasher ? hasher.apply(this, arguments) : key);
if (!_.has(cache, address)) {
cache[address] = new CacheObject(func, address, arguments, cache, this);
}
return cache[address].get();
};
memoize.cache = {};
return memoize;
};
function CacheObject(func, address, args, cache, context){
var self = this;
self.currentValue = null;
self.dep = new Tracker.Dependency();
self.numRun = 0;
//spawn a new autorun that keeps the value up-to-date
Tracker.nonreactive(function() {
Tracker.autorun(function(computation) {
//if this isn't the first run and nobody is listening,
//delete itself from cache and stop the computation
if (!computation.firstRun && !self.dep.hasDependents()){
computation.stop();
delete cache[address];
return;
}
//if we haven't run this before this flush, reset the counter after the flush
if(self.numRun === 0){
Tracker.afterFlush(function(){
self.numRun = 0;
});
}
self.numRun++;
//call the expensive function
//even if we don't use its value, we need to track its dependencies
var newValue = func.apply(context, args);
//prevent dependency loops, the memoized function shouldn't re-run
//more than once per flush
if (self.numRun > 1){
newValue = NaN;
if(_.isNaN(self.currentValue)) return;
}
//if the value changed, store the new value
if (self.currentValue !== newValue){
self.currentValue = newValue;
//tell the dependents that we've changed
self.dep.changed();
}
});
});
}
CacheObject.prototype.get = function() {
//if there is an active computation, track dependents
if (Tracker.active) this.dep.depend();
return this.currentValue;
};