mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge pull request #207 from NativeScript/feature/optimizations
Optimizations
This commit is contained in:
@@ -131,6 +131,9 @@
|
|||||||
<TypeScriptCompile Include="apps\tests\layouts\dock-layout-tests.ts" />
|
<TypeScriptCompile Include="apps\tests\layouts\dock-layout-tests.ts" />
|
||||||
<TypeScriptCompile Include="apps\tests\pages\app.ts" />
|
<TypeScriptCompile Include="apps\tests\pages\app.ts" />
|
||||||
<TypeScriptCompile Include="apps\tests\pages\file-load-test.ts" />
|
<TypeScriptCompile Include="apps\tests\pages\file-load-test.ts" />
|
||||||
|
<TypeScriptCompile Include="apps\tests\pages\page-load-performance\start.ts" />
|
||||||
|
<TypeScriptCompile Include="apps\tests\pages\page-load-performance\test-big.ts" />
|
||||||
|
<TypeScriptCompile Include="apps\tests\pages\page-load-performance\test-small.ts" />
|
||||||
<TypeScriptCompile Include="apps\tests\pages\page12.ts" />
|
<TypeScriptCompile Include="apps\tests\pages\page12.ts" />
|
||||||
<TypeScriptCompile Include="apps\tests\layouts\absolute-layout-tests.ts" />
|
<TypeScriptCompile Include="apps\tests\layouts\absolute-layout-tests.ts" />
|
||||||
<TypeScriptCompile Include="apps\tests\layouts\layout-helper.ts" />
|
<TypeScriptCompile Include="apps\tests\layouts\layout-helper.ts" />
|
||||||
@@ -618,6 +621,13 @@
|
|||||||
<Content Include="apps\TelerikNEXT\images\background.jpg" />
|
<Content Include="apps\TelerikNEXT\images\background.jpg" />
|
||||||
<Content Include="apps\template-settings\app.css" />
|
<Content Include="apps\template-settings\app.css" />
|
||||||
<Content Include="apps\tests\app\location-example.xml" />
|
<Content Include="apps\tests\app\location-example.xml" />
|
||||||
|
<Content Include="apps\tests\pages\page-load-performance\start.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Content>
|
||||||
|
<Content Include="apps\tests\pages\page-load-performance\test-big.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Content>
|
||||||
|
<Content Include="apps\tests\pages\page-load-performance\test-small.xml" />
|
||||||
<Content Include="apps\tests\pages\page18.xml" />
|
<Content Include="apps\tests\pages\page18.xml" />
|
||||||
<Content Include="apps\tests\ui\bindingContext_testPage.xml" />
|
<Content Include="apps\tests\ui\bindingContext_testPage.xml" />
|
||||||
<Content Include="apps\tests\ui\bindingContext_testPage1.xml" />
|
<Content Include="apps\tests\ui\bindingContext_testPage1.xml" />
|
||||||
|
|||||||
12
apps/tests/pages/performance-test/start.ts
Normal file
12
apps/tests/pages/performance-test/start.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import frame = require("ui/frame");
|
||||||
|
import observable = require("data/observable");
|
||||||
|
|
||||||
|
declare function __startCPUProfiler(name: string);
|
||||||
|
|
||||||
|
export function navigate(args: observable.EventData) {
|
||||||
|
var tag = "" + args.object.get("tag");
|
||||||
|
__startCPUProfiler("xml-performance-" + tag);
|
||||||
|
frame.topmost().navigate({
|
||||||
|
moduleName: tag,
|
||||||
|
});
|
||||||
|
}
|
||||||
7
apps/tests/pages/performance-test/start.xml
Normal file
7
apps/tests/pages/performance-test/start.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<Page loaded="pageLoaded" >
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="test small" tag="test-small" tap="navigate" />
|
||||||
|
<Button text="test big" tag="test-big" tap="navigate" />
|
||||||
|
<Button text="telerik next session" tag="telerik-next-session" tap="navigate" />
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
||||||
7
apps/tests/pages/performance-test/test-big.ts
Normal file
7
apps/tests/pages/performance-test/test-big.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import observable = require("data/observable");
|
||||||
|
|
||||||
|
declare function __stopCPUProfiler(name: string);
|
||||||
|
|
||||||
|
export function pageLoaded(args: observable.EventData) {
|
||||||
|
__stopCPUProfiler("xml-performance-test-big");
|
||||||
|
}
|
||||||
54
apps/tests/pages/performance-test/test-big.xml
Normal file
54
apps/tests/pages/performance-test/test-big.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<Page loaded="pageLoaded" unloaded="pageUnloaded" backgroundColor="red">
|
||||||
|
<StackLayout>
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="1button1" />
|
||||||
|
<Button text="1button2" />
|
||||||
|
<Button text="1button3" />
|
||||||
|
<Button text="1button4" />
|
||||||
|
<Button text="1button5" />
|
||||||
|
<Button text="1button6" />
|
||||||
|
<Button text="1button7" />
|
||||||
|
<Button text="1button8" />
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="2button1" />
|
||||||
|
<Button text="2button2" />
|
||||||
|
<Button text="2button3" />
|
||||||
|
<Button text="2button4" />
|
||||||
|
<Button text="2button5" />
|
||||||
|
<Button text="2button6" />
|
||||||
|
<Button text="2button7" />
|
||||||
|
<Button text="2button8" />
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="3button1" />
|
||||||
|
<Button text="3button2" />
|
||||||
|
<Button text="3button3" />
|
||||||
|
<Button text="3button4" />
|
||||||
|
<Button text="3button5" />
|
||||||
|
<Button text="3button6" />
|
||||||
|
<Button text="3button7" />
|
||||||
|
<Button text="3button8" />
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="4button1" />
|
||||||
|
<Button text="4button2" />
|
||||||
|
<Button text="4button3" />
|
||||||
|
<Button text="4button4" />
|
||||||
|
<Button text="4button5" />
|
||||||
|
<Button text="4button6" />
|
||||||
|
<Button text="4button7" />
|
||||||
|
<Button text="4button8" />
|
||||||
|
</StackLayout>
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="5button1" />
|
||||||
|
<Button text="5button2" />
|
||||||
|
<Button text="5button3" />
|
||||||
|
<Button text="5button4" />
|
||||||
|
<Button text="5button5" />
|
||||||
|
<Button text="5button6" />
|
||||||
|
<Button text="5button7" />
|
||||||
|
<Button text="5button8" />
|
||||||
|
</StackLayout>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
||||||
7
apps/tests/pages/performance-test/test-small.ts
Normal file
7
apps/tests/pages/performance-test/test-small.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import observable = require("data/observable");
|
||||||
|
|
||||||
|
declare function __stopCPUProfiler(name: string);
|
||||||
|
|
||||||
|
export function pageLoaded(args: observable.EventData) {
|
||||||
|
__stopCPUProfiler("xml-performance-test-small");
|
||||||
|
}
|
||||||
12
apps/tests/pages/performance-test/test-small.xml
Normal file
12
apps/tests/pages/performance-test/test-small.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<Page loaded="pageLoaded" unloaded="pageUnloaded" backgroundColor="green">
|
||||||
|
<StackLayout>
|
||||||
|
<Button text="button1" />
|
||||||
|
<Button text="button2" />
|
||||||
|
<Button text="button3" />
|
||||||
|
<Button text="button4" />
|
||||||
|
<Button text="button5" />
|
||||||
|
<Button text="button6" />
|
||||||
|
<Button text="button7" />
|
||||||
|
<Button text="button8" />
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
||||||
@@ -24,16 +24,16 @@ function validateRegisterParameters(name: string, ownerType: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPropertyByNameAndType(name: string, owner: any): Property {
|
function getPropertyByNameAndType(name: string, owner: any): Property {
|
||||||
var baseClasses = types.getBaseClasses(owner);
|
|
||||||
var i;
|
|
||||||
var result;
|
var result;
|
||||||
var key;
|
var key;
|
||||||
for (i = 0; i < baseClasses.length; i++) {
|
var classInfo = types.getClassInfo(owner);
|
||||||
key = generatePropertyKey(name, baseClasses[i]);
|
while (classInfo) {
|
||||||
|
key = generatePropertyKey(name, classInfo.name);
|
||||||
result = propertyFromKey[key];
|
result = propertyFromKey[key];
|
||||||
if (result) {
|
if (result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
classInfo = classInfo.baseClassInfo;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ import imageSource = require("image-source");
|
|||||||
import utils = require("utils/utils");
|
import utils = require("utils/utils");
|
||||||
|
|
||||||
// key is the property id and value is Dictionary<string, StylePropertyChangedHandler>;
|
// key is the property id and value is Dictionary<string, StylePropertyChangedHandler>;
|
||||||
var _registeredHandlers = {};
|
var _registeredHandlers = Array<Object>();
|
||||||
|
|
||||||
// key is a className + property id and value is StylePropertyChangedHandler;
|
// key is a className + property id and value is StylePropertyChangedHandler;
|
||||||
var _handlersCache = {};
|
var _handlersCache = {};
|
||||||
|
|
||||||
// classes like Frame that does not need to handle styling properties.
|
// classes like Frame that does not need to handle styling properties.
|
||||||
var noStylingClasses = {};
|
var noStylingClasses = {};
|
||||||
|
|
||||||
@@ -292,14 +294,14 @@ export function registerHandler(property: dependencyObservable.Property,
|
|||||||
handler: styling.stylers.StylePropertyChangedHandler,
|
handler: styling.stylers.StylePropertyChangedHandler,
|
||||||
className?: string) {
|
className?: string) {
|
||||||
var realClassName = className ? className : "default";
|
var realClassName = className ? className : "default";
|
||||||
if (_registeredHandlers.hasOwnProperty(property.id + "")) {
|
|
||||||
_registeredHandlers[property.id][realClassName] = handler;
|
var handlerRecord = _registeredHandlers[property.id];
|
||||||
}
|
if (!handlerRecord) {
|
||||||
else {
|
handlerRecord = {};
|
||||||
var handlerRecord = {};
|
|
||||||
handlerRecord[realClassName] = handler;
|
|
||||||
_registeredHandlers[property.id] = handlerRecord;
|
_registeredHandlers[property.id] = handlerRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlerRecord[realClassName] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerNoStylingClass(className) {
|
export function registerNoStylingClass(className) {
|
||||||
@@ -307,33 +309,38 @@ export function registerNoStylingClass(className) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getHandler(property: dependencyObservable.Property, view: view.View): styling.stylers.StylePropertyChangedHandler {
|
export function getHandler(property: dependencyObservable.Property, view: view.View): styling.stylers.StylePropertyChangedHandler {
|
||||||
var classNames = types.getBaseClasses(view);
|
return getHandlerInternal(property.id, types.getClassInfo(view));
|
||||||
// adding default as last class name if no other class is found default handler will be used
|
}
|
||||||
classNames.push("default");
|
|
||||||
if (_handlersCache.hasOwnProperty(classNames[0] + property.id)) {
|
function getHandlerInternal(propertyId: number, classInfo: types.ClassInfo): styling.stylers.StylePropertyChangedHandler {
|
||||||
return _handlersCache[classNames[0] + property.id];
|
var className = classInfo ? classInfo.name : "default";
|
||||||
|
var handlerKey = className + propertyId;
|
||||||
|
|
||||||
|
// try the cache first
|
||||||
|
var result = _handlersCache[handlerKey];
|
||||||
|
if (types.isDefined(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var propertyHandlers = _registeredHandlers[propertyId];
|
||||||
|
if (noStylingClasses.hasOwnProperty(className) || !propertyHandlers) {
|
||||||
|
// Reached 'no-styling' class or no property handlers are registered for this proeprtyID
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
else if (propertyHandlers.hasOwnProperty(className)) {
|
||||||
|
// Found handler for this class
|
||||||
|
result = propertyHandlers[className];
|
||||||
|
}
|
||||||
|
else if (classInfo) {
|
||||||
|
// Check the base class
|
||||||
|
result = getHandlerInternal(propertyId, classInfo.baseClassInfo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var i;
|
result = null;
|
||||||
var propertyHandlers;
|
|
||||||
var handler;
|
|
||||||
propertyHandlers = _registeredHandlers[property.id];
|
|
||||||
for (i = 0; i < classNames.length; i++) {
|
|
||||||
if (propertyHandlers) {
|
|
||||||
var loopClassName = classNames[i];
|
|
||||||
if (noStylingClasses.hasOwnProperty(loopClassName)) {
|
|
||||||
_handlersCache[loopClassName + property.id] = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (propertyHandlers.hasOwnProperty(loopClassName)) {
|
|
||||||
handler = propertyHandlers[loopClassName];
|
|
||||||
_handlersCache[loopClassName + property.id] = handler;
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
_handlersCache[handlerKey] = result;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property registration
|
// Property registration
|
||||||
|
|||||||
22
utils/types.d.ts
vendored
22
utils/types.d.ts
vendored
@@ -61,4 +61,26 @@
|
|||||||
* Return an array of strings with the name of all classes.
|
* Return an array of strings with the name of all classes.
|
||||||
*/
|
*/
|
||||||
export function getBaseClasses(object): Array<string>;
|
export function getBaseClasses(object): Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that gets the ClassInfo for an object.
|
||||||
|
* @param object The object for which the ClassInfo will be get.
|
||||||
|
* Returns a ClassInfo for the object.
|
||||||
|
*/
|
||||||
|
export function getClassInfo(object: Object): ClassInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Class holding information about a class
|
||||||
|
*/
|
||||||
|
export class ClassInfo {
|
||||||
|
/**
|
||||||
|
* Gets the name of the class.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ClassInfo for the base class of the current info.
|
||||||
|
*/
|
||||||
|
baseClassInfo: ClassInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -31,27 +31,71 @@ export function verifyCallback(value: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var classInfosMap = new Map<Function, ClassInfo>();
|
||||||
var funcNameRegex = /function (.{1,})\(/;
|
var funcNameRegex = /function (.{1,})\(/;
|
||||||
export function getClass(object): string {
|
export function getClass(object: Object): string {
|
||||||
var results = (funcNameRegex).exec((object).constructor.toString());
|
return getClassInfo(object).name;
|
||||||
return (results && results.length > 1) ? results[1] : "";
|
}
|
||||||
|
|
||||||
|
export function getClassInfo(object: Object): ClassInfo {
|
||||||
|
var constructor = object.constructor;
|
||||||
|
|
||||||
|
var result = classInfosMap.get(constructor);
|
||||||
|
if (!result) {
|
||||||
|
result = new ClassInfo(constructor);
|
||||||
|
classInfosMap.set(constructor, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBaseClasses(object): Array<string> {
|
export function getBaseClasses(object): Array<string> {
|
||||||
var baseProto = object.__proto__;
|
|
||||||
var result = [];
|
var result = [];
|
||||||
result.push(getClass(object));
|
var info = getClassInfo(object);
|
||||||
|
while (info) {
|
||||||
while (baseProto !== Object.prototype) {
|
result.push(info.name);
|
||||||
var baseProtoString = baseProto.toString();
|
info = info.baseClassInfo;
|
||||||
// while extending some classes for platform specific versions results in duplicate class types in hierarchy
|
}
|
||||||
if (result.indexOf(baseProtoString) === -1) {
|
return result;
|
||||||
result.push(baseProtoString);
|
}
|
||||||
}
|
|
||||||
baseProto = baseProto.__proto__;
|
export class ClassInfo {
|
||||||
|
private _typeCosntructor: Function;
|
||||||
|
private _name: string;
|
||||||
|
private _baseClassInfo: ClassInfo;
|
||||||
|
|
||||||
|
constructor(typeCosntructor: Function) {
|
||||||
|
this._typeCosntructor = typeCosntructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push("Object");
|
get name(): string {
|
||||||
|
if (!this._name) {
|
||||||
|
var results = (funcNameRegex).exec(this._typeCosntructor.toString());
|
||||||
|
this._name = (results && results.length > 1) ? results[1] : "";
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseClassInfo(): ClassInfo {
|
||||||
|
if (isUndefined(this._baseClassInfo)) {
|
||||||
|
this._baseClassInfo = ClassInfo._getBase(this);
|
||||||
|
|
||||||
|
// While extending some classes for platform specific versions results in duplicate class types in hierarchy.
|
||||||
|
if (this._baseClassInfo && this._baseClassInfo.name === this.name) {
|
||||||
|
this._baseClassInfo = ClassInfo._getBase(this._baseClassInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._baseClassInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _getBase(info: ClassInfo): ClassInfo {
|
||||||
|
var result = null;
|
||||||
|
var constructorProto = info._typeCosntructor.prototype;
|
||||||
|
if (constructorProto.__proto__) {
|
||||||
|
result = getClassInfo(constructorProto.__proto__);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user