Skip to content

Commit 40e603f

Browse files
author
Scott J. Miles
committed
micro-optimizations and code reductions
1 parent d69b2bc commit 40e603f

File tree

5 files changed

+97
-95
lines changed

5 files changed

+97
-95
lines changed

src/declaration/attributes.js

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,9 @@
77

88
// imports
99

10-
var api = scope.api.instance.attributes;
11-
12-
//var PUBLISHED = api.PUBLISHED;
13-
var INSTANCE_ATTRIBUTES = api.INSTANCE_ATTRIBUTES;
14-
1510
// magic words
1611

17-
var PUBLISH = 'publish';
18-
var ATTRIBUTES = 'attributes';
12+
var ATTRIBUTES_ATTRIBUTE = 'attributes';
1913

2014
// attributes api
2115

@@ -35,26 +29,12 @@
3529
inheritAttributesObjects: function(prototype) {
3630
// chain our LC property map to our inherited version
3731
chainObject(prototype._publishLC, prototype.__proto__._publishLC);
38-
prototype[INSTANCE_ATTRIBUTES] = {};
39-
chainObject(prototype[INSTANCE_ATTRIBUTES], prototype.__proto__[INSTANCE_ATTRIBUTES]);
40-
//this.inheritObject(prototype, PUBLISHED);
41-
//this.inheritObject(prototype, INSTANCE_ATTRIBUTES);
32+
prototype._instanceAttributes = {};
33+
chainObject(prototype._instanceAttributes, prototype.__proto__._instanceAttributes);
4234
},
43-
//
44-
parsePublished: function(prototype) {
45-
// transcribe `attributes` declarations onto own prototype's `publish`
46-
var publish = this.publishAttributes(prototype);
47-
// if we have any properties to publish
48-
if (publish) {
49-
// transcribe `publish` entries onto own prototype
50-
this.publishProperties(publish, prototype);
51-
// construct map of lower-cased property names
52-
prototype._publishLC = this.lowerCaseMap(publish);
53-
}
54-
},
55-
publishAttributes: function(prototype) {
35+
publishAttributes: function(prototype, base) {
5636
// merge names from 'attributes' attribute
57-
var attributes = this.getAttribute(ATTRIBUTES);
37+
var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE);
5838
if (attributes) {
5939
// get properties to publish
6040
var publish = prototype.publish || (prototype.publish = {});
@@ -65,32 +45,16 @@
6545
// remove excess ws
6646
n = names[i].trim();
6747
// do not override explicit entries
68-
if (publish[n] === undefined) {
48+
if (publish[n] === undefined && base[n] === undefined) {
6949
publish[n] = null;
7050
}
7151
}
7252
}
73-
return prototype.publish;
74-
},
75-
publishProperties: function(published, prototype) {
76-
// ensure a prototype value for each one
77-
for (var n in published) {
78-
if (prototype[n] === undefined) {
79-
prototype[n] = published[n];
80-
}
81-
}
82-
},
83-
lowerCaseMap: function(published) {
84-
var map = {};
85-
for (var n in published) {
86-
map[n.toLowerCase()] = n;
87-
}
88-
return map;
8953
},
9054
// record clonable attributes from <element>
9155
accumulateInstanceAttributes: function() {
9256
// inherit instance attributes
93-
var clonable = this.prototype[INSTANCE_ATTRIBUTES];
57+
var clonable = this.prototype._instanceAttributes;
9458
// merge attributes from element
9559
this.attributes.forEach(function(a) {
9660
if (this.isInstanceAttribute(a.name)) {
@@ -105,8 +69,8 @@
10569
blackList: {name: 1, 'extends': 1, constructor: 1, noscript: 1}
10670
};
10771

108-
// add ATTRIBUTES symbol to blacklist
109-
attributes.blackList[ATTRIBUTES] = 1;
72+
// add ATTRIBUTES_ATTRIBUTE to the blacklist
73+
attributes.blackList[ATTRIBUTES_ATTRIBUTE] = 1;
11074

11175
// exports
11276

src/declaration/properties.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,56 @@
1919
//console.log('inferring observe entry for', n);
2020
}
2121
}
22+
},
23+
optimizePropertyMaps: function(prototype, base) {
24+
if (prototype.observe) {
25+
// combine name list
26+
prototype._observeNames = Object.keys(prototype.observe).concat(base._observeNames || []);
27+
// build value list
28+
prototype._observeValues = valuesForNames(prototype._observeNames, prototype.observe);
29+
}
30+
if (prototype.publish) {
31+
// combine name list
32+
prototype._publishNames = Object.keys(prototype.publish).concat(base._publishNames || []);
33+
// build value list
34+
prototype._publishValues = valuesForNames(prototype._publishNames, prototype.publish);
35+
}
36+
},
37+
publishProperties: function(prototype, base) {
38+
// if we have any properties to publish
39+
var publish = prototype.publish;
40+
if (publish) {
41+
// transcribe `publish` entries onto own prototype
42+
this.requireProperties(publish, prototype, base);
43+
// construct map of lower-cased property names
44+
prototype._publishLC = this.lowerCaseMap(publish);
45+
}
46+
},
47+
requireProperties: function(properties, prototype, base) {
48+
// ensure a prototype value for each one
49+
for (var n in properties) {
50+
if (prototype[n] === undefined && base[n] === undefined) {
51+
prototype[n] = properties[n];
52+
}
53+
}
54+
},
55+
lowerCaseMap: function(properties) {
56+
var map = {};
57+
for (var n in properties) {
58+
map[n.toLowerCase()] = n;
59+
}
60+
return map;
2261
}
2362
};
2463

64+
function valuesForNames(names, map) {
65+
var values = [];
66+
for (var i=0, l=names.length; i<l; i++) {
67+
values[i] = map[names[i]];
68+
}
69+
return values;
70+
}
71+
2572
// exports
2673

2774
scope.api.declaration.properties = properties;

src/declaration/prototype.js

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// TODO(sjmiles): duplicated in attributes.js
1717
if (Object.__proto__) {
1818
var chainObject = function(object, inherited) {
19-
if (inherited && object !== inherited) {
19+
if (object && inherited && object !== inherited) {
2020
object.__proto__ = inherited;
2121
}
2222
}
@@ -32,17 +32,17 @@
3232
register: function(name, extendee) {
3333
// build prototype combining extendee, Polymer base, and named api
3434
this.prototype = this.buildPrototype(name, extendee);
35-
//console.log(this.prototype);
36-
// backref
35+
// back reference declaration element
36+
// TODO(sjmiles): replace `element` with `elementElement` or `declaration`
3737
this.prototype.element = this;
38+
// more declarative features
39+
this.desugar();
3840
// TODO(sorvell): install a helper method this.resolvePath to aid in
3941
// setting resource paths. e.g.
4042
// this.$.image.src = this.resolvePath('images/foo.png')
4143
// Potentially remove when spec bug is addressed.
4244
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
4345
this.addResolvePathApi();
44-
// more declarative features
45-
this.desugar();
4646
// under ShadowDOMPolyfill, transforms to approximate missing CSS features
4747
if (window.ShadowDOMPolyfill) {
4848
Platform.ShadowCSS.shimStyling(this.templateContent(), name, extendee);
@@ -55,29 +55,20 @@
5555
buildPrototype: function(name, extendee) {
5656
// get our custom prototype (before chaining)
5757
var prototype = scope.getRegisteredPrototype(name);
58-
// copy declared publish list to `publish` object
59-
// ensure `publish` names are on prototype
60-
this.parsePublished(prototype);
61-
// infer observers for `observe` list based on method names
62-
this.inferObservers(prototype);
6358
// get basal prototype
6459
var base = this.generateBasePrototype(extendee);
60+
// transcribe `attributes` declarations onto own prototype's `publish`
61+
this.publishAttributes(prototype, base);
62+
// `publish` properties to the prototype and to attribute watch
63+
this.publishProperties(prototype, base);
64+
// infer observers for `observe` list based on method names
65+
this.inferObservers(prototype);
6566
// chain observe object
66-
if (prototype.hasOwnProperty('observe')) {
67-
if (base.hasOwnProperty('observe')) {
68-
chainObject(prototype.observe, base.observe);
69-
}
70-
// combine name list
71-
prototype._observeNames = Object.keys(prototype.observe).concat(base._observeNames || []);
72-
}
67+
chainObject(prototype.observe, base.observe);
7368
// chain publish object
74-
if (prototype.hasOwnProperty('publish')) {
75-
if (base.hasOwnProperty('publish')) {
76-
chainObject(prototype.publish, base.publish);
77-
}
78-
// combine name list
79-
prototype._publishNames = Object.keys(prototype.publish).concat(base._publishNames || []);
80-
}
69+
chainObject(prototype.publish, base.publish);
70+
// build side-chained lists to optimize iterations
71+
this.optimizePropertyMaps(prototype, base);
8172
// chain custom api
8273
chainObject(prototype, base);
8374
// inherit publishing meta-data
@@ -112,15 +103,21 @@
112103
},
113104
// build prototype combining extendee, Polymer base, and named api
114105
generateBasePrototype: function(extnds) {
115-
// create a prototype based on tag-name extension
116-
var prototype = HTMLElement.getPrototypeForTag(extnds);
117-
// insert base api in inheritance chain (if needed)
118-
return this.ensureBaseApi(prototype);
106+
var prototype = memoizedBases[extnds];
107+
if (!prototype) {
108+
// create a prototype based on tag-name extension
109+
var prototype = HTMLElement.getPrototypeForTag(extnds);
110+
// insert base api in inheritance chain (if needed)
111+
prototype = this.ensureBaseApi(prototype);
112+
// memoize this base
113+
memoizedBases[extnds] = prototype;
114+
}
115+
return prototype;
119116
},
120117
// install Polymer instance api into prototype chain, as needed
121-
ensureBaseApi: function(prototype) {
118+
ensureBaseApi: function(prototype) {
122119
if (!prototype.PolymerBase) {
123-
prototype = Object.create(prototype);
120+
prototype = Object.create(prototype);
124121
// we need a unique copy of base api for each base prototype
125122
// therefore we 'extend' here instead of simply chaining
126123
// we could memoize instead, especially for the common cases,
@@ -150,6 +147,9 @@
150147
}
151148
};
152149

150+
// memoize base prototypes
151+
memoizedBases = {};
152+
153153
// On platforms that do not support __proto__ (version of IE), the prototype
154154
// chain of a custom element is simulated via installation of __proto__.
155155
// Although custom elements manages this, we install it here so it's

src/instance/attributes.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,11 @@
55
*/
66
(function(scope) {
77

8-
// magic words
9-
10-
var INSTANCE_ATTRIBUTES = '__instance_attributes';
11-
//var PUBLISHED = '__published';
12-
138
// instance api for attributes
149

1510
var attributes = {
16-
//PUBLISHED: PUBLISHED,
17-
INSTANCE_ATTRIBUTES: INSTANCE_ATTRIBUTES,
1811
copyInstanceAttributes: function () {
19-
var a$ = this[INSTANCE_ATTRIBUTES];
12+
var a$ = this._instanceAttributes;
2013
for (var k in a$) {
2114
this.setAttribute(k, a$[k]);
2215
}
@@ -94,9 +87,6 @@
9487
}
9588
};
9689

97-
var lowerCase = String.prototype.toLowerCase.call.bind(
98-
String.prototype.toLowerCase);
99-
10090
// exports
10191

10292
scope.api.instance.attributes = attributes;

src/instance/properties.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,30 @@
2727
// perhaps we can make it optional somehow
2828
//
2929
// add user's observers
30-
var n$ = this._observeNames;
30+
var n$ = this._observeNames, v$ = this._observeValues;
3131
if (n$) {
32-
for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
33-
var m = this.observe[n];
32+
for (var i=0, l=n$.length, n; i<l; i++) {
33+
n = n$[i];
3434
if (this.publish && (this.publish[n] !== undefined)) {
35-
this.observeBoth(n, m);
35+
this.observeBoth(n, v$[i]);
3636
} else {
37-
this.observeProperty(n, m);
37+
this.observeProperty(n, v$[i]);
3838
}
3939
}
4040
}
4141
// add observers for published properties
42-
var n$ = this._publishNames;
42+
var n$ = this._publishNames, v$ = this._publishValues;
4343
if (n$) {
44-
for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
44+
for (var i=0, l=n$.length, n; i<l; i++) {
45+
n = n$[i];
4546
if (!this.observe || (this.observe[n] === undefined)) {
46-
this.observeAttributeProperty(n, this.publish[n]);
47+
this.observeAttributeProperty(n, v$[i]);
4748
}
4849
}
4950
}
5051
},
5152
_observe: function(name, cb) {
52-
log.watch && console.log(LOG_OBSERVE, this.localName, name);
53+
log.observe && console.log(LOG_OBSERVE, this.localName, name);
5354
registerObserver(this, name,
5455
new PathObserver(this, name, cb));
5556
},

0 commit comments

Comments
 (0)