From 624513f64d5ab533a2380adc4fba9e42c76f300b Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Tue, 16 Oct 2018 18:56:28 -0700 Subject: [PATCH] Avoids using mixins for behaviors. (WIP) Experimental optimization to avoid using mixins for behaviors. --- lib/legacy/class.js | 191 +++++++++++++++++++++++++++++++----- lib/mixins/element-mixin.js | 9 +- 2 files changed, 172 insertions(+), 28 deletions(-) diff --git a/lib/legacy/class.js b/lib/legacy/class.js index 9201283e09..843b708d0d 100644 --- a/lib/legacy/class.js +++ b/lib/legacy/class.js @@ -9,6 +9,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN */ import { LegacyElementMixin } from './legacy-element-mixin.js'; +import { DomModule } from '../elements/dom-module.js'; let metaProps = { attached: true, @@ -22,6 +23,20 @@ let metaProps = { behaviors: true }; +function copyProperties(source, target) { + for (let p in source) { + // NOTE: cannot copy `metaProps` methods onto prototype at least because + // `super.ready` must be called and is not included in the user fn. + if (!(p in metaProps)) { + let pd = Object.getOwnPropertyDescriptor(source, p); + if (pd) { + Object.defineProperty(target, p, pd); + } + } + } +} + +// TODO(sorvell): this breaks `Polymer.mixinBehaviors`; should fix via factoring /** * Applies a "legacy" behavior or array of behaviors to the provided class. * @@ -96,8 +111,8 @@ function _mixinBehaviors(behaviors, klass) { for (let i=0; i= 0; i--) { + b = this.behaviors[i]; + if (b.hostAttributes) { + for (let a in b.hostAttributes) { + this._ensureAttribute(a, b.hostAttributes[a]); + } + } + } + } } /** @@ -211,6 +327,14 @@ function GenerateClassFromInfo(info, Base) { */ ready() { super.ready(); + if (this.behaviors) { + for (let i=0, b; i < this.behaviors.length; i++) { + b = this.behaviors[i]; + if (b.ready) { + b.ready.call(this); + } + } + } if (info.ready) { info.ready.call(this); } @@ -220,7 +344,14 @@ function GenerateClassFromInfo(info, Base) { * @return {void} */ attached() { - super.attached(); + if (this.behaviors) { + for (let i=0, b; i < this.behaviors.length; i++) { + b = this.behaviors[i]; + if (b.attached) { + b.attached.call(this); + } + } + } if (info.attached) { info.attached.call(this); } @@ -230,7 +361,14 @@ function GenerateClassFromInfo(info, Base) { * @return {void} */ detached() { - super.detached(); + if (this.behaviors) { + for (let i=0, b; i < this.behaviors.length; i++) { + b = this.behaviors[i]; + if (b.detached) { + b.detached.call(this); + } + } + } if (info.detached) { info.detached.call(this); } @@ -246,7 +384,14 @@ function GenerateClassFromInfo(info, Base) { * @return {void} */ attributeChanged(name, old, value) { - super.attributeChanged(name, old, value); + if (this.behaviors) { + for (let i=0, b; i < this.behaviors.length; i++) { + b = this.behaviors[i]; + if (b.attributeChanged) { + b.attributeChanged.call(this, name, old, value); + } + } + } if (info.attributeChanged) { info.attributeChanged.call(this, name, old, value); } @@ -255,16 +400,7 @@ function GenerateClassFromInfo(info, Base) { PolymerGenerated.generatedFrom = info; - for (let p in info) { - // NOTE: cannot copy `metaProps` methods onto prototype at least because - // `super.ready` must be called and is not included in the user fn. - if (!(p in metaProps)) { - let pd = Object.getOwnPropertyDescriptor(info, p); - if (pd) { - Object.defineProperty(PolymerGenerated.prototype, p, pd); - } - } - } + copyProperties(info, PolymerGenerated.prototype); return PolymerGenerated; } @@ -343,12 +479,13 @@ export const Class = function(info, mixin) { if (!info) { console.warn(`Polymer's Class function requires \`info\` argument`); } - const baseWithBehaviors = info.behaviors ? - // note: mixinBehaviors ensures `LegacyElementMixin`. - mixinBehaviors(info.behaviors, HTMLElement) : - LegacyElementMixin(HTMLElement); - const baseWithMixin = mixin ? mixin(baseWithBehaviors) : baseWithBehaviors; - const klass = GenerateClassFromInfo(info, baseWithMixin); + const base = mixin ? mixin(LegacyElementMixin(HTMLElement)) : + LegacyElementMixin(HTMLElement); + let klass = class extends base {}; + if (info.behaviors) { + mixinBehaviors(info.behaviors, klass); + } + klass = GenerateClassFromInfo(info, klass); // decorate klass with registration info klass.is = info.is; return klass; diff --git a/lib/mixins/element-mixin.js b/lib/mixins/element-mixin.js index f07ce7f9e3..4e302c75a0 100644 --- a/lib/mixins/element-mixin.js +++ b/lib/mixins/element-mixin.js @@ -228,7 +228,14 @@ export const ElementMixin = dedupingMixin(base => { } // always add observer if (info.observer) { - proto._createPropertyObserver(name, info.observer, allProps[info.observer]); + if (Array.isArray(info.observer)) { + for (let i=0; i < info.observer.length; i++) { + const o = info.observer[i]; + proto._createPropertyObserver(name, o, allProps[o]); + } + } else { + proto._createPropertyObserver(name, info.observer, allProps[info.observer]); + } } // always create the mapping from attribute back to property for deserialization. proto._addPropertyToAttributeMap(name);