mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 12:58:38 +08:00 
			
		
		
		
	perf: property optimizations (#10850)
This commit is contained in:
		@ -12,9 +12,16 @@ import { calc } from '@csstools/css-calc';
 | 
				
			|||||||
export { unsetValue } from './property-shared';
 | 
					export { unsetValue } from './property-shared';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cssPropertyNames: string[] = [];
 | 
					const cssPropertyNames: string[] = [];
 | 
				
			||||||
 | 
					const HAS_OWN = Object.prototype.hasOwnProperty;
 | 
				
			||||||
const symbolPropertyMap = {};
 | 
					const symbolPropertyMap = {};
 | 
				
			||||||
const cssSymbolPropertyMap = {};
 | 
					const cssSymbolPropertyMap = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hoisted regex/constants for hot paths to avoid re-allocation
 | 
				
			||||||
 | 
					const CSS_VARIABLE_NAME_RE = /^--[^,\s]+?$/;
 | 
				
			||||||
 | 
					const DIP_RE = /([0-9]+(\.[0-9]+)?)dip\b/g;
 | 
				
			||||||
 | 
					const UNSET_RE = /unset/g;
 | 
				
			||||||
 | 
					const INFINITY_RE = /infinity/g;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const inheritableProperties = new Array<InheritedProperty<any, any>>();
 | 
					const inheritableProperties = new Array<InheritedProperty<any, any>>();
 | 
				
			||||||
const inheritableCssProperties = new Array<InheritedCssProperty<any, any>>();
 | 
					const inheritableCssProperties = new Array<InheritedCssProperty<any, any>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -50,7 +57,7 @@ export function _getStyleProperties(): CssProperty<any, any>[] {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function isCssVariable(property: string) {
 | 
					export function isCssVariable(property: string) {
 | 
				
			||||||
	return /^--[^,\s]+?$/.test(property);
 | 
						return CSS_VARIABLE_NAME_RE.test(property);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function isCssCalcExpression(value: string) {
 | 
					export function isCssCalcExpression(value: string) {
 | 
				
			||||||
@ -119,27 +126,31 @@ export function _evaluateCssCalcExpression(value: string) {
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return value;
 | 
							return value;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return value;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function _replaceDip(value: string) {
 | 
					function _replaceDip(value: string) {
 | 
				
			||||||
	return value.replace(/([0-9]+(\.[0-9]+)?)dip\b/g, '$1');
 | 
						return value.replace(DIP_RE, '$1');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function _replaceKeywordsWithValues(value: string) {
 | 
					function _replaceKeywordsWithValues(value: string) {
 | 
				
			||||||
	let cssValue = value;
 | 
						let cssValue = value;
 | 
				
			||||||
	if (cssValue.includes('unset')) {
 | 
						if (cssValue.includes('unset')) {
 | 
				
			||||||
		cssValue = cssValue.replace(/unset/g, '0');
 | 
							cssValue = cssValue.replace(UNSET_RE, '0');
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (cssValue.includes('infinity')) {
 | 
						if (cssValue.includes('infinity')) {
 | 
				
			||||||
		cssValue = cssValue.replace(/infinity/g, '999999');
 | 
							cssValue = cssValue.replace(INFINITY_RE, '999999');
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return cssValue;
 | 
						return cssValue;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getPropertiesFromMap(map): Property<any, any>[] | CssProperty<any, any>[] {
 | 
					function getPropertiesFromMap(map): Property<any, any>[] | CssProperty<any, any>[] {
 | 
				
			||||||
	const props = [];
 | 
						const symbols = Object.getOwnPropertySymbols(map);
 | 
				
			||||||
	Object.getOwnPropertySymbols(map).forEach((symbol) => props.push(map[symbol]));
 | 
						const len = symbols.length;
 | 
				
			||||||
 | 
						const props = new Array(len);
 | 
				
			||||||
 | 
						for (let i = 0; i < len; i++) {
 | 
				
			||||||
 | 
							props[i] = map[symbols[i]];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return props;
 | 
						return props;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -240,15 +251,13 @@ export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<
 | 
				
			|||||||
							if (this._suspendedUpdates) {
 | 
												if (this._suspendedUpdates) {
 | 
				
			||||||
								this._suspendedUpdates[propertyName] = property;
 | 
													this._suspendedUpdates[propertyName] = property;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} else {
 | 
											} else if (defaultValueKey in this) {
 | 
				
			||||||
							if (defaultValueKey in this) {
 | 
					 | 
				
			||||||
							this[setNative](this[defaultValueKey]);
 | 
												this[setNative](this[defaultValueKey]);
 | 
				
			||||||
							delete this[defaultValueKey];
 | 
												delete this[defaultValueKey];
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							this[setNative](defaultValue);
 | 
												this[setNative](defaultValue);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this[key] = value;
 | 
										this[key] = value;
 | 
				
			||||||
					if (valueChanged) {
 | 
										if (valueChanged) {
 | 
				
			||||||
@ -424,15 +433,13 @@ export class CoercibleProperty<T extends ViewBase, U> extends Property<T, U> imp
 | 
				
			|||||||
							if (this._suspendedUpdates) {
 | 
												if (this._suspendedUpdates) {
 | 
				
			||||||
								this._suspendedUpdates[propertyName] = property;
 | 
													this._suspendedUpdates[propertyName] = property;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} else {
 | 
											} else if (defaultValueKey in this) {
 | 
				
			||||||
							if (defaultValueKey in this) {
 | 
					 | 
				
			||||||
							this[setNative](this[defaultValueKey]);
 | 
												this[setNative](this[defaultValueKey]);
 | 
				
			||||||
							delete this[defaultValueKey];
 | 
												delete this[defaultValueKey];
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							this[setNative](defaultValue);
 | 
												this[setNative](defaultValue);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this[key] = value;
 | 
										this[key] = value;
 | 
				
			||||||
					if (valueChanged) {
 | 
										if (valueChanged) {
 | 
				
			||||||
@ -577,7 +584,10 @@ export class CssProperty<T extends Style, U> {
 | 
				
			|||||||
		const propertyName = options.name;
 | 
							const propertyName = options.name;
 | 
				
			||||||
		this.name = propertyName;
 | 
							this.name = propertyName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Guard against undefined cssName
 | 
				
			||||||
 | 
							if (options.cssName) {
 | 
				
			||||||
			cssPropertyNames.push(options.cssName);
 | 
								cssPropertyNames.push(options.cssName);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.cssName = `css:${options.cssName}`;
 | 
							this.cssName = `css:${options.cssName}`;
 | 
				
			||||||
		this.cssLocalName = options.cssName;
 | 
							this.cssLocalName = options.cssName;
 | 
				
			||||||
@ -657,15 +667,13 @@ export class CssProperty<T extends Style, U> {
 | 
				
			|||||||
							if (view._suspendedUpdates) {
 | 
												if (view._suspendedUpdates) {
 | 
				
			||||||
								view._suspendedUpdates[propertyName] = property;
 | 
													view._suspendedUpdates[propertyName] = property;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} else {
 | 
											} else if (defaultValueKey in this) {
 | 
				
			||||||
							if (defaultValueKey in this) {
 | 
					 | 
				
			||||||
							view[setNative](this[defaultValueKey]);
 | 
												view[setNative](this[defaultValueKey]);
 | 
				
			||||||
							delete this[defaultValueKey];
 | 
												delete this[defaultValueKey];
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							view[setNative](defaultValue);
 | 
												view[setNative](defaultValue);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this[key] = value;
 | 
										this[key] = value;
 | 
				
			||||||
					if (valueChanged) {
 | 
										if (valueChanged) {
 | 
				
			||||||
@ -743,15 +751,13 @@ export class CssProperty<T extends Style, U> {
 | 
				
			|||||||
							if (view._suspendedUpdates) {
 | 
												if (view._suspendedUpdates) {
 | 
				
			||||||
								view._suspendedUpdates[propertyName] = property;
 | 
													view._suspendedUpdates[propertyName] = property;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} else {
 | 
											} else if (defaultValueKey in this) {
 | 
				
			||||||
							if (defaultValueKey in this) {
 | 
					 | 
				
			||||||
							view[setNative](this[defaultValueKey]);
 | 
												view[setNative](this[defaultValueKey]);
 | 
				
			||||||
							delete this[defaultValueKey];
 | 
												delete this[defaultValueKey];
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							view[setNative](defaultValue);
 | 
												view[setNative](defaultValue);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this[key] = value;
 | 
										this[key] = value;
 | 
				
			||||||
					if (valueChanged) {
 | 
										if (valueChanged) {
 | 
				
			||||||
@ -856,7 +862,9 @@ export class CssAnimationProperty<T extends Style, U> implements CssAnimationPro
 | 
				
			|||||||
		const propertyName = options.name;
 | 
							const propertyName = options.name;
 | 
				
			||||||
		this.name = propertyName;
 | 
							this.name = propertyName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (options.cssName) {
 | 
				
			||||||
			cssPropertyNames.push(options.cssName);
 | 
								cssPropertyNames.push(options.cssName);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		CssAnimationProperty.properties[propertyName] = this;
 | 
							CssAnimationProperty.properties[propertyName] = this;
 | 
				
			||||||
		if (options.cssName && options.cssName !== propertyName) {
 | 
							if (options.cssName && options.cssName !== propertyName) {
 | 
				
			||||||
@ -1143,8 +1151,7 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
 | 
				
			|||||||
							if (view._suspendedUpdates) {
 | 
												if (view._suspendedUpdates) {
 | 
				
			||||||
								view._suspendedUpdates[propertyName] = property;
 | 
													view._suspendedUpdates[propertyName] = property;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						} else {
 | 
											} else if (unsetNativeValue) {
 | 
				
			||||||
							if (unsetNativeValue) {
 | 
					 | 
				
			||||||
							if (defaultValueKey in this) {
 | 
												if (defaultValueKey in this) {
 | 
				
			||||||
								view[setNative](this[defaultValueKey]);
 | 
													view[setNative](this[defaultValueKey]);
 | 
				
			||||||
								delete this[defaultValueKey];
 | 
													delete this[defaultValueKey];
 | 
				
			||||||
@ -1159,7 +1166,6 @@ export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U>
 | 
				
			|||||||
							view[setNative](value);
 | 
												view[setNative](value);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if (this.hasListeners(eventName)) {
 | 
										if (this.hasListeners(eventName)) {
 | 
				
			||||||
						this.notify<PropertyChangeData>({
 | 
											this.notify<PropertyChangeData>({
 | 
				
			||||||
@ -1356,6 +1362,7 @@ export function applyPendingNativeSetters(view: ViewBase): void {
 | 
				
			|||||||
	// TODO: Check what happens if a view was suspended and its value was reset, or set back to default!
 | 
						// TODO: Check what happens if a view was suspended and its value was reset, or set back to default!
 | 
				
			||||||
	const suspendedUpdates = view._suspendedUpdates;
 | 
						const suspendedUpdates = view._suspendedUpdates;
 | 
				
			||||||
	for (const propertyName in suspendedUpdates) {
 | 
						for (const propertyName in suspendedUpdates) {
 | 
				
			||||||
 | 
							if (!HAS_OWN.call(suspendedUpdates, propertyName)) continue;
 | 
				
			||||||
		const property = <PropertyInterface>suspendedUpdates[propertyName];
 | 
							const property = <PropertyInterface>suspendedUpdates[propertyName];
 | 
				
			||||||
		const setNative = property.setNative;
 | 
							const setNative = property.setNative;
 | 
				
			||||||
		if (view[setNative]) {
 | 
							if (view[setNative]) {
 | 
				
			||||||
@ -1523,9 +1530,11 @@ export function propagateInheritableCssProperties(parentStyle: Style, childStyle
 | 
				
			|||||||
export function getSetProperties(view: ViewBase): [string, any][] {
 | 
					export function getSetProperties(view: ViewBase): [string, any][] {
 | 
				
			||||||
	const result = [];
 | 
						const result = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Object.getOwnPropertyNames(view).forEach((prop) => {
 | 
						const ownProps = Object.getOwnPropertyNames(view);
 | 
				
			||||||
 | 
						for (let i = 0; i < ownProps.length; i++) {
 | 
				
			||||||
 | 
							const prop = ownProps[i];
 | 
				
			||||||
		result.push([prop, view[prop]]);
 | 
							result.push([prop, view[prop]]);
 | 
				
			||||||
	});
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const symbols = Object.getOwnPropertySymbols(view);
 | 
						const symbols = Object.getOwnPropertySymbols(view);
 | 
				
			||||||
	for (const symbol of symbols) {
 | 
						for (const symbol of symbols) {
 | 
				
			||||||
@ -1545,8 +1554,10 @@ export function getComputedCssValues(view: ViewBase): [string, any][] {
 | 
				
			|||||||
	const result = [];
 | 
						const result = [];
 | 
				
			||||||
	const style = view.style;
 | 
						const style = view.style;
 | 
				
			||||||
	for (const prop of cssPropertyNames) {
 | 
						for (const prop of cssPropertyNames) {
 | 
				
			||||||
 | 
							if (prop !== undefined && prop !== null) {
 | 
				
			||||||
			result.push([prop, style[prop]]);
 | 
								result.push([prop, style[prop]]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add these to enable box model in chrome-devtools styles tab
 | 
						// Add these to enable box model in chrome-devtools styles tab
 | 
				
			||||||
	result.push(['top', 'auto']);
 | 
						result.push(['top', 'auto']);
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user