Skip to content

Commit 701bfea

Browse files
authored
perf: property optimizations (NativeScript#10850)
1 parent 440ae0e commit 701bfea

File tree

1 file changed

+60
-49
lines changed
  • packages/core/ui/core/properties

1 file changed

+60
-49
lines changed

packages/core/ui/core/properties/index.ts

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@ import { calc } from '@csstools/css-calc';
1212
export { unsetValue } from './property-shared';
1313

1414
const cssPropertyNames: string[] = [];
15+
const HAS_OWN = Object.prototype.hasOwnProperty;
1516
const symbolPropertyMap = {};
1617
const cssSymbolPropertyMap = {};
1718

19+
// Hoisted regex/constants for hot paths to avoid re-allocation
20+
const CSS_VARIABLE_NAME_RE = /^--[^,\s]+?$/;
21+
const DIP_RE = /([0-9]+(\.[0-9]+)?)dip\b/g;
22+
const UNSET_RE = /unset/g;
23+
const INFINITY_RE = /infinity/g;
24+
1825
const inheritableProperties = new Array<InheritedProperty<any, any>>();
1926
const inheritableCssProperties = new Array<InheritedCssProperty<any, any>>();
2027

@@ -50,7 +57,7 @@ export function _getStyleProperties(): CssProperty<any, any>[] {
5057
}
5158

5259
export function isCssVariable(property: string) {
53-
return /^--[^,\s]+?$/.test(property);
60+
return CSS_VARIABLE_NAME_RE.test(property);
5461
}
5562

5663
export function isCssCalcExpression(value: string) {
@@ -119,27 +126,31 @@ export function _evaluateCssCalcExpression(value: string) {
119126
} else {
120127
return value;
121128
}
129+
return value;
122130
}
123131

124132
function _replaceDip(value: string) {
125-
return value.replace(/([0-9]+(\.[0-9]+)?)dip\b/g, '$1');
133+
return value.replace(DIP_RE, '$1');
126134
}
127135

128136
function _replaceKeywordsWithValues(value: string) {
129137
let cssValue = value;
130138
if (cssValue.includes('unset')) {
131-
cssValue = cssValue.replace(/unset/g, '0');
139+
cssValue = cssValue.replace(UNSET_RE, '0');
132140
}
133141
if (cssValue.includes('infinity')) {
134-
cssValue = cssValue.replace(/infinity/g, '999999');
142+
cssValue = cssValue.replace(INFINITY_RE, '999999');
135143
}
136144
return cssValue;
137145
}
138146

139147
function getPropertiesFromMap(map): Property<any, any>[] | CssProperty<any, any>[] {
140-
const props = [];
141-
Object.getOwnPropertySymbols(map).forEach((symbol) => props.push(map[symbol]));
142-
148+
const symbols = Object.getOwnPropertySymbols(map);
149+
const len = symbols.length;
150+
const props = new Array(len);
151+
for (let i = 0; i < len; i++) {
152+
props[i] = map[symbols[i]];
153+
}
143154
return props;
144155
}
145156

@@ -240,13 +251,11 @@ export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<
240251
if (this._suspendedUpdates) {
241252
this._suspendedUpdates[propertyName] = property;
242253
}
254+
} else if (defaultValueKey in this) {
255+
this[setNative](this[defaultValueKey]);
256+
delete this[defaultValueKey];
243257
} else {
244-
if (defaultValueKey in this) {
245-
this[setNative](this[defaultValueKey]);
246-
delete this[defaultValueKey];
247-
} else {
248-
this[setNative](defaultValue);
249-
}
258+
this[setNative](defaultValue);
250259
}
251260
}
252261
} else {
@@ -424,13 +433,11 @@ export class CoercibleProperty<T extends ViewBase, U> extends Property<T, U> imp
424433
if (this._suspendedUpdates) {
425434
this._suspendedUpdates[propertyName] = property;
426435
}
436+
} else if (defaultValueKey in this) {
437+
this[setNative](this[defaultValueKey]);
438+
delete this[defaultValueKey];
427439
} else {
428-
if (defaultValueKey in this) {
429-
this[setNative](this[defaultValueKey]);
430-
delete this[defaultValueKey];
431-
} else {
432-
this[setNative](defaultValue);
433-
}
440+
this[setNative](defaultValue);
434441
}
435442
}
436443
} else {
@@ -577,7 +584,10 @@ export class CssProperty<T extends Style, U> {
577584
const propertyName = options.name;
578585
this.name = propertyName;
579586

580-
cssPropertyNames.push(options.cssName);
587+
// Guard against undefined cssName
588+
if (options.cssName) {
589+
cssPropertyNames.push(options.cssName);
590+
}
581591

582592
this.cssName = `css:${options.cssName}`;
583593
this.cssLocalName = options.cssName;
@@ -657,13 +667,11 @@ export class CssProperty<T extends Style, U> {
657667
if (view._suspendedUpdates) {
658668
view._suspendedUpdates[propertyName] = property;
659669
}
670+
} else if (defaultValueKey in this) {
671+
view[setNative](this[defaultValueKey]);
672+
delete this[defaultValueKey];
660673
} else {
661-
if (defaultValueKey in this) {
662-
view[setNative](this[defaultValueKey]);
663-
delete this[defaultValueKey];
664-
} else {
665-
view[setNative](defaultValue);
666-
}
674+
view[setNative](defaultValue);
667675
}
668676
}
669677
} else {
@@ -743,13 +751,11 @@ export class CssProperty<T extends Style, U> {
743751
if (view._suspendedUpdates) {
744752
view._suspendedUpdates[propertyName] = property;
745753
}
754+
} else if (defaultValueKey in this) {
755+
view[setNative](this[defaultValueKey]);
756+
delete this[defaultValueKey];
746757
} else {
747-
if (defaultValueKey in this) {
748-
view[setNative](this[defaultValueKey]);
749-
delete this[defaultValueKey];
750-
} else {
751-
view[setNative](defaultValue);
752-
}
758+
view[setNative](defaultValue);
753759
}
754760
}
755761
} else {
@@ -856,7 +862,9 @@ export class CssAnimationProperty<T extends Style, U> implements CssAnimationPro
856862
const propertyName = options.name;
857863
this.name = propertyName;
858864

859-
cssPropertyNames.push(options.cssName);
865+
if (options.cssName) {
866+
cssPropertyNames.push(options.cssName);
867+
}
860868

861869
CssAnimationProperty.properties[propertyName] = this;
862870
if (options.cssName && options.cssName !== propertyName) {
@@ -1143,21 +1151,19 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
11431151
if (view._suspendedUpdates) {
11441152
view._suspendedUpdates[propertyName] = property;
11451153
}
1146-
} else {
1147-
if (unsetNativeValue) {
1148-
if (defaultValueKey in this) {
1149-
view[setNative](this[defaultValueKey]);
1150-
delete this[defaultValueKey];
1151-
} else {
1152-
view[setNative](defaultValue);
1153-
}
1154+
} else if (unsetNativeValue) {
1155+
if (defaultValueKey in this) {
1156+
view[setNative](this[defaultValueKey]);
1157+
delete this[defaultValueKey];
11541158
} else {
1155-
if (!(defaultValueKey in this)) {
1156-
this[defaultValueKey] = view[getDefault] ? view[getDefault]() : defaultValue;
1157-
}
1158-
1159-
view[setNative](value);
1159+
view[setNative](defaultValue);
11601160
}
1161+
} else {
1162+
if (!(defaultValueKey in this)) {
1163+
this[defaultValueKey] = view[getDefault] ? view[getDefault]() : defaultValue;
1164+
}
1165+
1166+
view[setNative](value);
11611167
}
11621168
}
11631169

@@ -1356,6 +1362,7 @@ export function applyPendingNativeSetters(view: ViewBase): void {
13561362
// TODO: Check what happens if a view was suspended and its value was reset, or set back to default!
13571363
const suspendedUpdates = view._suspendedUpdates;
13581364
for (const propertyName in suspendedUpdates) {
1365+
if (!HAS_OWN.call(suspendedUpdates, propertyName)) continue;
13591366
const property = <PropertyInterface>suspendedUpdates[propertyName];
13601367
const setNative = property.setNative;
13611368
if (view[setNative]) {
@@ -1523,9 +1530,11 @@ export function propagateInheritableCssProperties(parentStyle: Style, childStyle
15231530
export function getSetProperties(view: ViewBase): [string, any][] {
15241531
const result = [];
15251532

1526-
Object.getOwnPropertyNames(view).forEach((prop) => {
1533+
const ownProps = Object.getOwnPropertyNames(view);
1534+
for (let i = 0; i < ownProps.length; i++) {
1535+
const prop = ownProps[i];
15271536
result.push([prop, view[prop]]);
1528-
});
1537+
}
15291538

15301539
const symbols = Object.getOwnPropertySymbols(view);
15311540
for (const symbol of symbols) {
@@ -1545,7 +1554,9 @@ export function getComputedCssValues(view: ViewBase): [string, any][] {
15451554
const result = [];
15461555
const style = view.style;
15471556
for (const prop of cssPropertyNames) {
1548-
result.push([prop, style[prop]]);
1557+
if (prop !== undefined && prop !== null) {
1558+
result.push([prop, style[prop]]);
1559+
}
15491560
}
15501561

15511562
// Add these to enable box model in chrome-devtools styles tab

0 commit comments

Comments
 (0)