Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(ivy): support className in micro benchmarks #33392

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions karma-js.conf.js
Expand Up @@ -79,6 +79,7 @@ module.exports = function(config) {
'dist/all/@angular/compiler/test/render3/**',
'dist/all/@angular/core/test/bundling/**',
'dist/all/@angular/core/test/render3/ivy/**',
'dist/all/@angular/core/test/render3/perf/**',
'dist/all/@angular/elements/schematics/**',
'dist/all/@angular/examples/**/e2e_test/*',
'dist/all/@angular/language-service/**',
Expand Down
10 changes: 9 additions & 1 deletion packages/core/test/render3/perf/BUILD.bazel
@@ -1,6 +1,6 @@
package(default_visibility = ["//visibility:private"])

load("//tools:defaults.bzl", "ng_rollup_bundle", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test", "ng_rollup_bundle", "ts_library")

ts_library(
name = "perf_lib",
Expand All @@ -9,10 +9,18 @@ ts_library(
),
deps = [
"//packages/core",
"@npm//@types/jasmine",
"@npm//@types/node",
],
)

jasmine_node_test(
name = "perf",
deps = [
":perf_lib",
],
)

ng_rollup_bundle(
name = "class_binding",
entry_point = ":class_binding/index.ts",
Expand Down
60 changes: 50 additions & 10 deletions packages/core/test/render3/perf/noop_renderer.ts
Expand Up @@ -7,23 +7,24 @@
*/
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3} from '../../../src/render3/interfaces/renderer';

export class WebWorkerRenderNode implements RNode, RComment, RText {
export class MicroBenchmarkRenderNode implements RNode, RComment, RText {
textContent: string|null = null;
parentNode: RNode|null = null;
parentElement: RElement|null = null;
nextSibling: RNode|null = null;
removeChild(oldChild: RNode): RNode { return oldChild; }
insertBefore(newChild: RNode, refChild: RNode|null, isViewRoot: boolean): void {}
appendChild(newChild: RNode): RNode { return newChild; }
className: string = '';
}

export class NoopRenderer implements ProceduralRenderer3 {
export class MicroBenchmarkRenderer implements ProceduralRenderer3 {
destroy(): void { throw new Error('Method not implemented.'); }
createComment(value: string): RComment { return new WebWorkerRenderNode(); }
createComment(value: string): RComment { return new MicroBenchmarkRenderNode(); }
createElement(name: string, namespace?: string|null|undefined): RElement {
return new WebWorkerRenderNode() as any as RElement;
return new MicroBenchmarkRenderNode() as any as RElement;
}
createText(value: string): RText { return new WebWorkerRenderNode(); }
createText(value: string): RText { return new MicroBenchmarkRenderNode(); }
destroyNode?: ((node: RNode) => void)|null|undefined;
appendChild(parent: RElement, newChild: RNode): void {}
insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void {}
Expand All @@ -32,10 +33,21 @@ export class NoopRenderer implements ProceduralRenderer3 {
parentNode(node: RNode): RElement|null { throw new Error('Method not implemented.'); }
nextSibling(node: RNode): RNode|null { throw new Error('Method not implemented.'); }
setAttribute(el: RElement, name: string, value: string, namespace?: string|null|undefined): void {
if (name === 'class' && isOurNode(el)) {
el.className = value;
}
}
removeAttribute(el: RElement, name: string, namespace?: string|null|undefined): void {}
addClass(el: RElement, name: string): void {}
removeClass(el: RElement, name: string): void {}
addClass(el: RElement, name: string): void {
if (isOurNode(el)) {
el.className = el.className === '' ? name : remove(el.className, name) + ' ' + name;
}
}
removeClass(el: RElement, name: string): void {
if (isOurNode(el)) {
el.className = remove(el.className, name);
}
}
setStyle(el: RElement, style: string, value: any, flags?: RendererStyleFlags3|undefined): void {}
removeStyle(el: RElement, style: string, flags?: RendererStyleFlags3|undefined): void {}
setProperty(el: RElement, name: string, value: any): void {}
Expand All @@ -47,11 +59,39 @@ export class NoopRenderer implements ProceduralRenderer3 {
}
}

export class NoopRendererFactory implements RendererFactory3 {
export class MicroBenchmarkRendererFactory implements RendererFactory3 {
createRenderer(hostElement: RElement|null, rendererType: null): Renderer3 {
if (typeof global !== 'undefined') {
(global as any).Node = WebWorkerRenderNode;
(global as any).Node = MicroBenchmarkRenderNode;
}
return new NoopRenderer();
return new MicroBenchmarkRenderer();
}
}

function isOurNode(node: any): node is MicroBenchmarkRenderNode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear why do we need the isOurNode check - wouldn't we always run with the MicroBenchmarkRender that produces the same types of nodes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is was there for type narrowing. Otherwise I need to do casting in TS to make it happy

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. Could you leave a comment on this function so a next person doesn't remove it (I as about to attempt to do just this :-) )

return node instanceof MicroBenchmarkRenderNode;
}

const enum Code {
SPACE = 32,
}

function remove(text: string, key: string): string {
let wasLastWhitespace = true;
for (let i = 0; i < text.length; i++) {
if (wasLastWhitespace) {
const start = i;
let same = true;
let k = 0;
while (k < key.length && (same = text.charCodeAt(i) === key.charCodeAt(k))) {
k++;
i++;
}
if (same && text.charCodeAt(i) == Code.SPACE) {
return text.substring(0, start) + text.substring(i + 1);
}
}
wasLastWhitespace = text.charCodeAt(i) <= Code.SPACE;
}
return text;
}
38 changes: 38 additions & 0 deletions packages/core/test/render3/perf/noop_renderer_spec.ts
@@ -0,0 +1,38 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {ProceduralRenderer3} from '@angular/core/src/render3/interfaces/renderer';

import {MicroBenchmarkRenderNode, MicroBenchmarkRendererFactory} from './noop_renderer';

describe('MicroBenchmarkRenderNode', () => {
const renderer =
new MicroBenchmarkRendererFactory().createRenderer(null, null) as ProceduralRenderer3;
describe('className', () => {
it('should be available in global space', () => {
expect(Node).toBeDefined();
const node: any = new MicroBenchmarkRenderNode();
expect(node instanceof Node).toBeTruthy();
});

it('should emulate className', () => {
const node: any = new MicroBenchmarkRenderNode();
expect(node.className).toBe('');
renderer.setAttribute(node, 'foo', 'A AA BBB');
expect(node.className).toBe('');
renderer.setAttribute(node, 'class', 'A AA BBB');
expect(node.className).toBe('A AA BBB');
renderer.addClass(node, 'A');
expect(node.className).toBe('AA BBB A');
renderer.addClass(node, 'C');
expect(node.className).toBe('AA BBB A C');
renderer.removeClass(node, 'A');
expect(node.className).toBe('AA BBB C');
});
});
});
5 changes: 3 additions & 2 deletions packages/core/test/render3/perf/setup.ts
Expand Up @@ -12,10 +12,11 @@ import {RendererFactory3, domRendererFactory3} from '../../../src/render3/interf
import {LView, LViewFlags, TView} from '../../../src/render3/interfaces/view';
import {insertView} from '../../../src/render3/node_manipulation';

import {NoopRendererFactory} from './noop_renderer';
import {MicroBenchmarkRendererFactory} from './noop_renderer';

const isBrowser = typeof process === 'undefined';
const rendererFactory: RendererFactory3 = isBrowser ? domRendererFactory3 : new NoopRendererFactory;
const rendererFactory: RendererFactory3 =
isBrowser ? domRendererFactory3 : new MicroBenchmarkRendererFactory;
const renderer = rendererFactory.createRenderer(null, null);

export function createAndRenderLView(
Expand Down