perf(ivy): avoid using array splice (#31656)

PR Close #31656
This commit is contained in:
Pawel Kozlowski 2019-07-19 15:42:08 +02:00 committed by Miško Hevery
parent ce196105ce
commit 8b26447c4f
5 changed files with 38 additions and 29 deletions

View File

@ -7,8 +7,8 @@
*/ */
import {ViewEncapsulation} from '../metadata/view'; import {ViewEncapsulation} from '../metadata/view';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertDefined, assertDomNode} from '../util/assert'; import {assertDefined, assertDomNode} from '../util/assert';
import {assertLContainer, assertLView} from './assert'; import {assertLContainer, assertLView} from './assert';
import {attachPatchData} from './context_discovery'; import {attachPatchData} from './context_discovery';
import {CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container';
@ -209,7 +209,7 @@ export function insertView(lView: LView, lContainer: LContainer, index: number)
} }
if (index < containerLength - CONTAINER_HEADER_OFFSET) { if (index < containerLength - CONTAINER_HEADER_OFFSET) {
lView[NEXT] = lContainer[indexInContainer]; lView[NEXT] = lContainer[indexInContainer];
lContainer.splice(CONTAINER_HEADER_OFFSET + index, 0, lView); addToArray(lContainer, CONTAINER_HEADER_OFFSET + index, lView);
} else { } else {
lContainer.push(lView); lContainer.push(lView);
lView[NEXT] = null; lView[NEXT] = null;
@ -260,7 +260,7 @@ function detachMovedView(declarationContainer: LContainer, lView: LView) {
/** /**
* Detaches a view from a container. * Detaches a view from a container.
* *
* This method splices the view from the container's array of active views. It also * This method removes the view from the container's array of active views. It also
* removes the view's elements from the DOM. * removes the view's elements from the DOM.
* *
* @param lContainer The container from which to detach a view * @param lContainer The container from which to detach a view
@ -283,7 +283,7 @@ export function detachView(lContainer: LContainer, removeIndex: number): LView|u
if (removeIndex > 0) { if (removeIndex > 0) {
lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT] as LView; lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT] as LView;
} }
const removedLView = lContainer.splice(CONTAINER_HEADER_OFFSET + removeIndex, 1)[0]; const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex);
addRemoveViewFromContainer(viewToDetach, false); addRemoveViewFromContainer(viewToDetach, false);
// notify query that a view has been removed // notify query that a view has been removed

View File

@ -15,8 +15,8 @@ import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Renderer2} from '../render/api'; import {Renderer2} from '../render/api';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertDefined, assertGreaterThan, assertLessThan} from '../util/assert'; import {assertDefined, assertGreaterThan, assertLessThan} from '../util/assert';
import {assertLContainer} from './assert'; import {assertLContainer} from './assert';
import {NodeInjector, getParentInjectorLocation} from './di'; import {NodeInjector, getParentInjectorLocation} from './di';
import {addToViewTree, createEmbeddedViewAndNode, createLContainer, renderEmbeddedTemplate} from './instructions/shared'; import {addToViewTree, createEmbeddedViewAndNode, createLContainer, renderEmbeddedTemplate} from './instructions/shared';
@ -201,8 +201,8 @@ export function createContainerRef(
} }
clear(): void { clear(): void {
while (this.length) { while (this.length > 0) {
this.remove(0); this.remove(this.length - 1);
} }
} }
@ -259,7 +259,7 @@ export function createContainerRef(
addRemoveViewFromContainer(lView, true, beforeNode); addRemoveViewFromContainer(lView, true, beforeNode);
(viewRef as ViewRef<any>).attachToViewContainerRef(this); (viewRef as ViewRef<any>).attachToViewContainerRef(this);
this._lContainer[VIEW_REFS] !.splice(adjustedIdx, 0, viewRef); addToArray(this._lContainer[VIEW_REFS] !, adjustedIdx, viewRef);
return viewRef; return viewRef;
} }
@ -284,14 +284,16 @@ export function createContainerRef(
this.allocateContainerIfNeeded(); this.allocateContainerIfNeeded();
const adjustedIdx = this._adjustIndex(index, -1); const adjustedIdx = this._adjustIndex(index, -1);
removeView(this._lContainer, adjustedIdx); removeView(this._lContainer, adjustedIdx);
this._lContainer[VIEW_REFS] !.splice(adjustedIdx, 1); removeFromArray(this._lContainer[VIEW_REFS] !, adjustedIdx);
} }
detach(index?: number): viewEngine_ViewRef|null { detach(index?: number): viewEngine_ViewRef|null {
this.allocateContainerIfNeeded(); this.allocateContainerIfNeeded();
const adjustedIdx = this._adjustIndex(index, -1); const adjustedIdx = this._adjustIndex(index, -1);
const view = detachView(this._lContainer, adjustedIdx); const view = detachView(this._lContainer, adjustedIdx);
const wasDetached = view && this._lContainer[VIEW_REFS] !.splice(adjustedIdx, 1)[0] != null;
const wasDetached =
view && removeFromArray(this._lContainer[VIEW_REFS] !, adjustedIdx) != null;
return wasDetached ? new ViewRef(view !, view ![CONTEXT], -1) : null; return wasDetached ? new ViewRef(view !, view ![CONTEXT], -1) : null;
} }

View File

@ -43,3 +43,21 @@ export function flatten(list: any[], dst?: any[]): any[] {
export function deepForEach<T>(input: (T | any[])[], fn: (value: T) => void): void { export function deepForEach<T>(input: (T | any[])[], fn: (value: T) => void): void {
input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value)); input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value));
} }
export function addToArray(arr: any[], index: number, value: any): void {
// perf: array.push is faster than array.splice!
if (index >= arr.length) {
arr.push(value);
} else {
arr.splice(index, 0, value);
}
}
export function removeFromArray(arr: any[], index: number): any {
// perf: array.pop is faster than array.splice!
if (index >= arr.length - 1) {
return arr.pop();
} else {
return arr.splice(index, 1)[0];
}
}

View File

@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {addToArray, removeFromArray} from '../util/array_utils';
import {ElementData, NodeDef, NodeFlags, Services, ViewData, ViewDefinition, ViewState} from './types'; import {ElementData, NodeDef, NodeFlags, Services, ViewData, ViewDefinition, ViewState} from './types';
import {RenderNodeAction, declaredViewContainer, isComponentView, renderNode, visitRootRenderNodes} from './util'; import {RenderNodeAction, declaredViewContainer, renderNode, visitRootRenderNodes} from './util';
export function attachEmbeddedView( export function attachEmbeddedView(
parentView: ViewData, elementData: ElementData, viewIndex: number | undefined | null, parentView: ViewData, elementData: ElementData, viewIndex: number | undefined | null,
@ -133,21 +134,3 @@ function renderAttachEmbeddedView(
export function renderDetachView(view: ViewData) { export function renderDetachView(view: ViewData) {
visitRootRenderNodes(view, RenderNodeAction.RemoveChild, null, null, undefined); visitRootRenderNodes(view, RenderNodeAction.RemoveChild, null, null, undefined);
} }
function addToArray(arr: any[], index: number, value: any) {
// perf: array.push is faster than array.splice!
if (index >= arr.length) {
arr.push(value);
} else {
arr.splice(index, 0, value);
}
}
function removeFromArray(arr: any[], index: number) {
// perf: array.pop is faster than array.splice!
if (index >= arr.length - 1) {
arr.pop();
} else {
arr.splice(index, 1);
}
}

View File

@ -443,6 +443,9 @@
{ {
"name": "addRemoveViewFromContainer" "name": "addRemoveViewFromContainer"
}, },
{
"name": "addToArray"
},
{ {
"name": "addToViewTree" "name": "addToViewTree"
}, },
@ -1205,6 +1208,9 @@
{ {
"name": "registerPreOrderHooks" "name": "registerPreOrderHooks"
}, },
{
"name": "removeFromArray"
},
{ {
"name": "removeListeners" "name": "removeListeners"
}, },