relu-core
Version:
96 lines (81 loc) • 2.13 kB
JavaScript
var base = require("./base");
var rpConst = require("./const");
module.exports = function rpComputed(fn) {
var p = base();
p.constructor = rpComputed;
var value;
var dependencies
var scope;
p._get = function() {
if(!dependencies) calculateValue();
p.depend();
return value;
};
p._getUndependend = function() {
if(!dependencies) calculateValue();
return value;
};
p._length = function() {
if(!Array.isArray(value)) return -1;
return value.length;
};
p.isConst = function() {
return !dependencies || dependencies.every(function(dep) {
return dep.isConst();
});
};
p._writable = false;
var disposed = false;
p.onceDisposed(function() {
disposed = true;
if(dependencies) disconnect();
});
calculateValue();
function disconnect() {
var _scope = scope.slice();
var _deps = dependencies;
dependencies = scope = undefined;
for(var i = 0; i < _deps.length; i++) {
var dep = _deps[i];
dep.removeOnceChangedListener(onDependencyChanged);
dep.unref(p);
}
base.unrefAll(_scope);
}
function calculateValue() {
if(disposed) return;
var captured = base.capture(fn);
dependencies = captured.dependencies;
// if any of the dependencies is disposed, we are in a undefined state
for(var i = 0; i < dependencies.length; i++) {
if(dependencies[i].isDisposed()) {
dependencies.length = 0;
captured.value = undefined;
}
}
scope = captured.scope;
base.refAll(dependencies, p);
for(var i = 0; i < dependencies.length; i++)
dependencies[i].onceChanged(onDependencyChanged);
var val = captured.value;
if(val !== value) {
var old = value;
value = val;
p._updated(value, old);
p._changed();
}
}
function onDependencyChanged() {
if(!dependencies) return;
var temp = {};
var _deps = base.refAll(dependencies.slice(), temp);
var _scope = base.refAll(scope.slice(), temp);
disconnect();
base.atAtomicEnd(function() {
calculateValue();
base.unrefAll(_deps, temp);
base.unrefAll(_scope, temp);
});
}
return p;
};