From 24e647e0f75eaa18b740d62ffa06d1354352da7a Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Tue, 9 Jun 2015 11:57:50 -0700 Subject: [PATCH] perf(render): precompute # bound text nodes and root nodes in `DomProtoView` --- modules/angular2/src/dom/html_adapter.dart | 2 +- modules/angular2/src/render/dom/dom_renderer.ts | 15 +++++++-------- .../angular2/src/render/dom/view/proto_view.ts | 10 +++++++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/angular2/src/dom/html_adapter.dart b/modules/angular2/src/dom/html_adapter.dart index 5e350952e7..18bfd0e08e 100644 --- a/modules/angular2/src/dom/html_adapter.dart +++ b/modules/angular2/src/dom/html_adapter.dart @@ -102,7 +102,7 @@ class Html5LibDomAdapter implements DomAdapter { throw 'not implemented'; } content(node) { - throw 'not implemented'; + return node; } firstChild(el) => el is NodeList ? el.first : el.firstChild; diff --git a/modules/angular2/src/render/dom/dom_renderer.ts b/modules/angular2/src/render/dom/dom_renderer.ts index 5618e97717..05655a1a8c 100644 --- a/modules/angular2/src/render/dom/dom_renderer.ts +++ b/modules/angular2/src/render/dom/dom_renderer.ts @@ -224,13 +224,11 @@ export class DomRenderer extends Renderer { rootElementClone = DOM.importIntoDoc(DOM.content(protoView.element)); elementsWithBindingsDynamic = DOM.querySelectorAll(rootElementClone, NG_BINDING_CLASS_SELECTOR); - var childNode = DOM.firstChild(rootElementClone); - // TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView - viewRootNodes = []; + viewRootNodes = ListWrapper.createFixedSize(protoView.rootNodeCount); // Note: An explicit loop is the fastest way to convert a DOM array into a JS array! - while (childNode != null) { - ListWrapper.push(viewRootNodes, childNode); - childNode = DOM.nextSibling(childNode); + var childNode = DOM.firstChild(rootElementClone); + for (var i = 0; i < protoView.rootNodeCount; i++, childNode = DOM.nextSibling(childNode)) { + viewRootNodes[i] = childNode; } } else { rootElementClone = DOM.importIntoDoc(protoView.element); @@ -239,8 +237,9 @@ export class DomRenderer extends Renderer { } var binders = protoView.elementBinders; - var boundTextNodes = []; + var boundTextNodes = ListWrapper.createFixedSize(protoView.boundTextNodeCount); var boundElements = ListWrapper.createFixedSize(binders.length); + var boundTextNodeIdx = 0; for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) { var binder = binders[binderIdx]; @@ -261,7 +260,7 @@ export class DomRenderer extends Renderer { // boundTextNodes var textNodeIndices = binder.textNodeIndices; for (var i = 0; i < textNodeIndices.length; i++) { - ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]); + boundTextNodes[boundTextNodeIdx++] = childNodes[textNodeIndices[i]]; } // contentTags diff --git a/modules/angular2/src/render/dom/view/proto_view.ts b/modules/angular2/src/render/dom/view/proto_view.ts index 631d5a6afe..efccce804d 100644 --- a/modules/angular2/src/render/dom/view/proto_view.ts +++ b/modules/angular2/src/render/dom/view/proto_view.ts @@ -1,7 +1,7 @@ import {isPresent} from 'angular2/src/facade/lang'; import {DOM} from 'angular2/src/dom/dom_adapter'; -import {List} from 'angular2/src/facade/collection'; +import {List, ListWrapper} from 'angular2/src/facade/collection'; import {ElementBinder} from './element_binder'; import {NG_BINDING_CLASS} from '../util'; @@ -27,6 +27,8 @@ export class DomProtoView { rootBindingOffset: number; // the number of content tags seen in this or any child proto view. transitiveContentTagCount: number; + boundTextNodeCount: number; + rootNodeCount: number; constructor({elementBinders, element, transitiveContentTagCount}) { this.element = element; @@ -35,5 +37,11 @@ export class DomProtoView { this.isTemplateElement = DOM.isTemplateElement(this.element); this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0; + this.boundTextNodeCount = + ListWrapper.reduce(elementBinders, (prevCount: number, elementBinder: ElementBinder) => + prevCount + elementBinder.textNodeIndices.length, + 0); + this.rootNodeCount = + this.isTemplateElement ? DOM.childNodes(DOM.content(this.element)).length : 1; } }