61 lines
1.8 KiB
JavaScript
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 10 times per flush
|
|
if (self.numRun > 10){
|
|
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;
|
|
};
|