Make emboxValue dumb; explicitly stop autoruns

This commit is contained in:
David Greenspan
2014-03-20 09:39:13 -07:00
parent 6e945e29e7
commit c910fce4c6
3 changed files with 47 additions and 94 deletions

View File

@@ -24,7 +24,7 @@ Spacebars.include = function (templateOrFunction, contentBlock, elseContentBlock
var func = templateOrFunction;
var emboxedFunc = UI.emboxValue(func);
return function () {
var f = function () {
var tmpl = emboxedFunc();
if (tmpl === null)
@@ -34,6 +34,12 @@ Spacebars.include = function (templateOrFunction, contentBlock, elseContentBlock
return tmpl.extend(props);
};
f.stop = function () {
emboxedFunc.stop();
};
return f;
};
// Executes `{{foo bar baz}}` when called on `(foo, bar, baz)`.

View File

@@ -3,12 +3,17 @@ UI.If = function (argFunc, contentBlock, elseContentBlock) {
checkBlockHelperArguments('If', argFunc, contentBlock, elseContentBlock);
var emboxedCondition = emboxCondition(argFunc);
return function () {
var f = function () {
if (emboxedCondition())
return contentBlock;
else
return elseContentBlock || null;
};
f.stop = function () {
emboxedCondition.stop();
};
return f;
};

View File

@@ -47,101 +47,45 @@ UI.Component.render = function () {
};
var Box = function (func, equals) {
this.func = func;
this.equals = equals;
this.hasCurResult = false;
this.curResult = null;
this.hasOldResult = false;
this.oldResult = null;
this.dep = new Deps.Dependency;
this.resultComputation = null; // only present when valid (uninvalidated)
// Dead boxes have no `resultComputation` and so can be GCed
this.alive = true;
};
Box.prototype.kill = function () {
if (this.resultComputation)
this.resultComputation.stop();
this.alive = false;
};
Box.prototype._depend = function () {
var self = this;
if (! self.dep)
self.dep = new Deps.Dependency;
self.func = func;
self.equals = equals;
var isNew = self.dep.depend();
if (isNew) {
// For the new dependent, schedule a task for after that dependent's
// invalidation time. The task kills this Box if it ever has no
// dependencies after afterFlush.
Deps.onInvalidate(function () {
if (self.alive && ! self.dep.hasDependents()) {
Deps.afterFlush(function () {
// use a second afterFlush to bump ourselves to the END of the
// flush, after computation re-runs have had a chance to
// re-establish their dependencies on our computation.
Deps.afterFlush(function () {
if (self.alive && ! self.dep.hasDependents())
self.kill();
});
});
}
});
}
};
self.curResult = null;
self.dep = new Deps.Dependency;
Box.prototype._calc = function () {
// Precondition: (! self.resultComputation) && (! self.hasCurResult)
// Postcondition: self.resultComputation && self.hasCurResult
var self = this;
self.resultComputation = Deps.nonreactive(function () {
// Use an autorun that only runs once to capture dependencies
// of running `func()`.
return Deps.autorun(function (c) {
if (c.firstRun) {
var func = self.func;
self.curResult = func(); // NOT `self.func()` (which binds `this`)
self.hasCurResult = true;
} else {
// second run
if (self.hasCurResult) {
self.oldResult = self.curResult;
self.hasOldResult = true;
}
self.hasCurResult = false;
self.resultComputation = null;
c.stop();
if (self.dep.hasDependents()) {
if (! self.hasOldResult) {
self.dep.changed();
} else {
// We have dependents and an old value to compare against,
// so we have to re-evaluate immediately.
self._calc();
var equals = self.equals;
if (! (equals ? equals(self.curResult, self.oldResult) :
self.curResult === self.oldResult)) {
self.dep.changed();
}
}
var func = self.func;
var newResult = func();
if (! c.firstRun) {
var equals = self.equals;
var oldResult = self.curResult;
if (equals ? equals(newResult, oldResult) :
newResult === oldResult) {
// same as last time
return;
}
}
self.curResult = newResult;
self.dep.changed();
});
});
};
Box.prototype.get = function () {
this._depend();
Box.prototype.stop = function () {
this.resultComputation.stop();
};
if (! this.hasCurResult)
this._calc();
Box.prototype.get = function () {
if (Deps.active && ! this.resultComputation.stopped)
this.dep.depend();
return this.curResult;
};
@@ -183,22 +127,14 @@ UI.emboxValue = function (funcOrValue, equals) {
if (typeof funcOrValue === 'function') {
var func = funcOrValue;
var box = null;
var box = new Box(func, equals);
var f = function () {
if (! (box && box.alive)) {
if (! Deps.active)
return func();
box = new Box(func, equals);
}
return box.get();
};
f.stop = function () {
if (box && box.alive)
box.kill();
box.stop();
};
return f;
@@ -416,6 +352,12 @@ var materialize = function (node, parent, before, parentComponent) {
range.removed = function () {
rangeUpdater.stop();
};
// XXXX HACK
if (Deps.active && node.stop) {
Deps.onInvalidate(function () {
node.stop();
});
}
insert(range, parent, before);
} else if (node instanceof HTML.Tag) {
var tagName = node.tagName;