Perform property effect binning in property-effects

This commit is contained in:
Kevin Schaaf
2016-07-07 12:59:31 -07:00
parent c3e5356635
commit c24fcbf073
3 changed files with 64 additions and 128 deletions

View File

@@ -21,9 +21,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
constructor(templateStamp, attributes, annotations) {
super(attributes, annotations);
this._currentEffects = null;
// Not a correct assign polyfill-- only use where proto's don't matter!
// _mixin: Object.assign ? Object.assign : Polymer.Utils.mixin,
this._mixin = Polymer.Utils.mixin;
this._effectUid = 0;
this.templateStamp = templateStamp ||
@@ -34,82 +31,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
addPropertyEffect(model, property, effect) {
model = this.getModel(model);
if (!model.setProperties) {
var lib = this;
model.setProperties = function(props, fromAbove) {
lib.setProperties(this, props, fromAbove);
};
model.set = model.notifyPath = function(prop, value) {
lib.set(this, prop, value);
};
}
super.addPropertyEffect.apply(this, arguments);
if (this._currentEffects) {
var effects = this._currentEffects[property] ||
(this._currentEffects[property] = []);
effects.push(effect);
}
}
_accumulateEffects(model, name, fn, args) {
model = this.getModel(model);
this._currentEffects = this._ensureEffects(model, name);
fn.apply(this, args);
this._currentEffects = null;
}
// -- read only ----------------------------------------------
createReadOnlyProperty(model, property) {
model = this.getModel(model);
super.createReadOnlyProperty.apply(this, arguments);
this._ensureEffects(model, '_isReadOnly')[property] = true;
}
// -- observer ----------------------------------------------
createObserver(model) {
this._accumulateEffects(model, '_observerEffects',
super.createObserver, arguments);
}
// -- notify ----------------------------------------------
createNotifyingProperty(model) {
this._accumulateEffects(model, '_notifyEffects',
super.createNotifyingProperty, arguments);
}
// -- reflect ----------------------------------------------
createReflectedProperty(model) {
this._accumulateEffects(model, '_annotationEffects',
super.createReflectedProperty, arguments);
}
// -- complexObserver ----------------------------------------------
createMultiObserver(model) {
this._accumulateEffects(model, '_observerEffects',
super.createMultiObserver, arguments);
}
// -- computed ----------------------------------------------
createComputedProperty(model) {
this._accumulateEffects(model, '_computedEffects',
super.createComputedProperty, arguments);
}
// -- annotation ----------------------------------------------
bindTemplate(model, template) {
this._accumulateEffects(model, '_annotationEffects',
super.bindTemplate, [model, template]);
}
// -- set properties machinery
setProperties(inst, props, fromAbove) {
@@ -158,7 +79,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// Run computed effects
var inputProps = changedProps;
var computedProps;
while (this._runEffects(inst, inst._computedEffects, inputProps)) {
while (this._runEffects(inst, Types.COMPUTE, inputProps)) {
this._mixin(oldProps, inst.__dataOld);
this._mixin(changedProps, inst.__dataPending);
computedProps = this._mixin(computedProps || {}, inst.__dataPending);
@@ -177,9 +98,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (runId == inst._runId) {
changedProps = inst.__interimData;
// Run annotation effects
this._runEffects(inst, inst._annotationEffects, changedProps);
this._runEffects(inst, Types.PROPAGATE, changedProps);
if (!inst._propertyEffectsActive) {
this._runEffects(inst, inst._annotationEffects, {__static__: true});
this._runEffects(inst, Types.PROPAGATE, {__static__: true});
}
// Recurse to clients
this._flushPropClients(inst);
@@ -187,7 +108,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (inst._propertyEffectsActive) {
inst.__interimData = null;
// Run observer effects
this._runEffects(inst, inst._observerEffects, changedProps, oldProps);
this._runEffects(inst, Types.OBSERVE, changedProps, oldProps);
}
}
}
@@ -268,8 +189,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
_runEffects(inst, effects, props, oldProps) {
_runEffects(inst, type, props, oldProps) {
var ran;
var effects = inst[type];
if (effects) {
var id = this._effectUid++;
for (var prop in props) {
@@ -332,6 +254,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
var Types = BatchedEffects.Types;
// export
Polymer.BatchedEffects = BatchedEffects;

View File

@@ -85,6 +85,17 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
_addObservedAttribute(model, name) {
var attrName = Polymer.CaseMap.camelToDashCase(name);
var ctor = model.constructor;
if (!ctor.hasOwnProperty('observedAttributes')) {
ctor.observedAttributes =
ctor.observedAttributes ?
ctor.observedAttributes.slice() : [];
}
ctor.observedAttributes.push(attrName);
}
}
// export

View File

@@ -46,34 +46,33 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// Prototype setup ----------------------------------------
addPropertyEffect(model, path, effect, readOnly) {
addPropertyEffect(model, path, type, effect) {
model = this.getModel(model);
var property = this._rootForPath(path);
var effects = this._ensureEffects(model, '_propertyEffects')[property];
// _propertyEffects only used to track whether an accessor has been created or not
var effects = this._ensureOwnMappedArray(model, '_propertyEffects')[property];
if (!effects) {
effects = model._propertyEffects[property] = [];
// TODO(sorvell): kosher to bail here if an accessor already exists?
if (!readOnly && model.hasOwnProperty(property)) {
console.warn('Accessor already exists for', property, 'on', model);
} else {
this.createAccessor(model, property, readOnly);
}
if (!readOnly) {
this._addObservedAttribute(model, property);
}
this.createAccessor(model, property, type == Types.READ_ONLY);
}
if (effect && !readOnly) {
// effects are accumulated into arrays per property based on type
if (effect) {
effect.path = path;
effects.push(effect);
effects = this._ensureOwnMappedArray(model, type)[property];
if (!effects) {
effects = model[type][property] = [];
}
effects.push(effect);
}
}
_ensureEffects(model, name) {
var effects = model[name];
_ensureOwnMappedArray(model, type) {
var effects = model[type];
if (!effects) {
effects = model[name] = {};
} else if (!model.hasOwnProperty(name)) {
effects = model[name] = Object.create(model[name]);
effects = model[type] = {};
} else if (!model.hasOwnProperty(type)) {
effects = model[type] = Object.create(model[type]);
for (var p in effects) {
// TODO(kschaaf): replace with fast array copy #!%&$!
effects[p] = effects[p].slice();
@@ -87,17 +86,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return (dot < 0) ? path : path.slice(0, dot);
}
_addObservedAttribute(model, name) {
var attrName = Polymer.CaseMap.camelToDashCase(name);
var ctor = model.constructor;
if (!ctor.hasOwnProperty('observedAttributes')) {
ctor.observedAttributes =
ctor.observedAttributes ?
ctor.observedAttributes.slice() : [];
}
ctor.observedAttributes.push(attrName);
}
// Runtime ----------------------------------------
setProperty(inst, property, value) {
@@ -133,15 +121,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
// TODO(kschaaf): rather than create+run, consider closing over
// run in create to avoid extra info object creation, otoh maybe
// its good for debugging?
// -- readOnly ----------------------------------------------
createReadOnlyProperty(model, property, privateSetter) {
model = this.getModel(model);
this.addPropertyEffect(model, property, null, true);
this.addPropertyEffect(model, property, Types.READ_ONLY);
var lib = this;
if (privateSetter) {
model['_set' + this._upper(property)] = function(value) {
@@ -157,7 +141,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// -- observer ----------------------------------------------
createObserver(model, property, methodName, context) {
this.addPropertyEffect(model, property, {
this.addPropertyEffect(model, property, Types.OBSERVE, {
fn: this._runObserverEffect,
info: {
methodName: methodName,
@@ -178,7 +162,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// -- notify ----------------------------------------------
createNotifyingProperty(model, property) {
this.addPropertyEffect(model, property, {
this.addPropertyEffect(model, property, Types.NOTIFY, {
fn: this._runNotifyEffect,
info: {
lib: this,
@@ -197,7 +181,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// -- reflect ----------------------------------------------
createReflectedProperty(model, property) {
this.addPropertyEffect(model, property, {
this.addPropertyEffect(model, property, Types.PROPAGATE, {
fn: this._runReflectEffect,
info: {
lib: this,
@@ -214,7 +198,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
createMultiObserver(model, expression) {
var sig = this._parseMethod(expression);
this._createMethodEffect(model, sig, this._runMultiObserverEffect);
this._createMethodEffect(model, sig, Types.OBSERVE,
this._runMultiObserverEffect);
}
_runMultiObserverEffect(property, value, old, info) {
@@ -225,7 +210,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
createComputedProperty(model, property, expression) {
var sig = this._parseMethod(expression);
this._createMethodEffect(model, sig, this._runComputedEffect, property);
this._createMethodEffect(model, sig, Types.COMPUTE,
this._runComputedEffect, property);
}
_runComputedEffect(property, value, old, info) {
@@ -257,7 +243,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (part.signature) {
this._addAnnotatedComputationEffect(model, note, part, index);
} else if (!part.literal) {
this.addPropertyEffect(model, part.rootProperty, {
this.addPropertyEffect(model, part.rootProperty, Types.PROPAGATE, {
fn: this._runAnnotationEffect,
info: {
lib: this,
@@ -345,7 +331,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
_addAnnotatedComputationEffect(model, note, part, index) {
this._createMethodEffect(model, part.signature,
this._createMethodEffect(model, part.signature, Types.PROPAGATE,
this._runAnnotationComputationEffect, {
index: index,
isCompound: note.isCompound,
@@ -492,6 +478,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
_pathMatchesEffect(path, effect) {
var effectArg = effect.path;
return (effectArg == path) ||
(effectArg.indexOf(path + '.') === 0) ||
(/* effect.trigger.wildcard && */ path.indexOf(effectArg) === 0);
}
_fixPath(property, root, path) {
return property + path.slice(root.length);
}
@@ -502,7 +495,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// -- for method-based effects (complexObserver & computed) --------------
_createMethodEffect(model, sig, effectFn, methodInfo) {
_createMethodEffect(model, sig, type, effectFn, methodInfo) {
var dynamicFn = sig.dynamicFn;
var info = {
lib: this,
@@ -512,20 +505,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
dynamicFn: dynamicFn
};
if (sig.static) {
this.addPropertyEffect(model, '__static__', {
this.addPropertyEffect(model, '__static__', type, {
fn: effectFn, info: info
});
} else {
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
if (!arg.literal) {
this.addPropertyEffect(model, arg.rootProperty, {
this.addPropertyEffect(model, arg.rootProperty, type, {
fn: effectFn, info: info
});
}
}
}
if (dynamicFn) {
this._addPropertyEffect(model, sig.methodName, {
this._addPropertyEffect(model, sig.methodName, type, {
fn: effectFn, info: info
});
}
@@ -701,6 +694,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
var Types = PropertyEffects.Types = {
COMPUTE: '_computeEffects',
NOTIFY: '_notifyEffects',
PROPAGATE: '_propagateEffects',
OBSERVE: '_observeEffects',
READ_ONLY: '_readOnly'
}
// export
Polymer.PropertyEffects = PropertyEffects;