Skip to content

Commit

Permalink
feat(vdom): bring back optimization for singular text nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
localvoid committed Oct 18, 2018
1 parent ed562f4 commit b39555d
Show file tree
Hide file tree
Showing 56 changed files with 978 additions and 709 deletions.
2 changes: 1 addition & 1 deletion packages/ivi-gestures/src/touch_event_listener.ts
Expand Up @@ -71,7 +71,7 @@ export function createTouchEventListener(
const touches = ev.touches;
if (pointers.size >= touches.length) {
const canceledPointers: GesturePointerEvent[] = [];
pointers.forEach((pointer) => {
pointers.forEach(pointer => {
const id = pointer.id;
if (id !== 1) {
if (!findTouch(touches, id - TOUCH_ID_OFFSET)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/ivi-router/src/index.ts
Expand Up @@ -20,11 +20,11 @@ export function initRouter<A, T>(
}
};

window.addEventListener("popstate", (ev) => {
window.addEventListener("popstate", ev => {
goTo(location.pathname);
});

afterNativeEvent(EVENT_DISPATCHER_CLICK, (ev) => {
afterNativeEvent(EVENT_DISPATCHER_CLICK, ev => {
if ((ev.flags & (SyntheticEventFlags.PreventedDefault | SyntheticEventFlags.StoppedPropagation)) === 0) {
const anchor = findAnchorNode(ev.target as Element);
if (anchor !== null) {
Expand Down
6 changes: 3 additions & 3 deletions packages/ivi-state/src/__tests__/computed_query.spec.ts
Expand Up @@ -16,14 +16,14 @@ test(`should return value when executed`, () => {

test(`previous value should be null`, () => {
let p;
computedQuery((prev) => (p = prev, 0)).get();
computedQuery(prev => (p = prev, 0)).get();
expect(p).toBeNull();
});

test(`previous value should be cached`, () => {
let p;

const v = computedQuery((prev) => (p = prev, { a: 1337 }));
const v = computedQuery(prev => (p = prev, { a: 1337 }));
const a = v.get();
v.get();

Expand All @@ -33,7 +33,7 @@ test(`previous value should be cached`, () => {
test(`should reset previous value`, () => {
let p;

const v = computedQuery((prev) => (p = prev, { a: 1337 }));
const v = computedQuery(prev => (p = prev, { a: 1337 }));
v.get();
v.reset();
v.get();
Expand Down
4 changes: 2 additions & 2 deletions packages/ivi-test/src/query.ts
Expand Up @@ -131,7 +131,7 @@ function componentMatcherFactory(component: StatefulComponent<any>): VNodeCompon

export function query(wrapper: VNodeWrapper, predicate: Predicate<VNodeWrapper>): VNodeWrapper | null {
let result: VNodeWrapper | null = null;
visitWrapped(wrapper, (n) => {
visitWrapped(wrapper, n => {
if (wrapper !== n && predicate(n) === true) {
result = n;
return true;
Expand All @@ -143,7 +143,7 @@ export function query(wrapper: VNodeWrapper, predicate: Predicate<VNodeWrapper>)

export function queryAll(wrapper: VNodeWrapper, predicate: Predicate<VNodeWrapper>): VNodeWrapper[] {
const result: VNodeWrapper[] = [];
visitWrapped(wrapper, (n) => {
visitWrapped(wrapper, n => {
if (wrapper !== n && predicate(n) === true) {
result.push(n);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ivi-test/src/utils.ts
Expand Up @@ -10,8 +10,8 @@ import { EventHandler, EventDispatcher, VNode, VNodeFlags } from "ivi";
export function containsClassName(classNames: string, className: string): boolean {
return classNames
.split(" ")
.map((c) => c.trim())
.some((c) => c === className);
.map(c => c.trim())
.some(c => c === className);
}

/**
Expand Down
58 changes: 31 additions & 27 deletions packages/ivi-test/src/vdom.ts
Expand Up @@ -26,17 +26,19 @@ export function visitUnwrapped(
)) !== 0) {
let child = vnode._c;
if ((flags & VNodeFlags.Element) !== 0) {
while (child !== null) {
if (visitUnwrapped(child, vnode, context, visitor)) {
return true;
if ((flags & VNodeFlags.Children) !== 0) {
while (child !== null) {
if (visitUnwrapped(child as VNode, vnode, context, visitor)) {
return true;
}
child = (child as VNode)._r;
}
child = child._r;
}
} else {
if ((flags & VNodeFlags.UpdateContext) !== 0) {
context = { ...context, ...vnode._p };
}
return visitUnwrapped(child!, vnode, context, visitor);
return visitUnwrapped(child as VNode, vnode, context, visitor);
}
}

Expand All @@ -63,17 +65,19 @@ export function visitWrapped(
let context = wrapper.context;
let child = vnode._c;
if ((flags & VNodeFlags.Element) !== 0) {
while (child !== null) {
if (visitWrapped(new VNodeWrapper(child, wrapper, context), visitor)) {
return true;
if ((flags & VNodeFlags.Children) !== 0) {
while (child !== null) {
if (visitWrapped(new VNodeWrapper(child as VNode, wrapper, context), visitor)) {
return true;
}
child = (child as VNode)._r;
}
child = child._r;
}
} else {
if ((flags & VNodeFlags.UpdateContext) !== 0) {
context = { ...context, ...vnode._p };
}
return visitWrapped(new VNodeWrapper(child!, wrapper, context), visitor);
return visitWrapped(new VNodeWrapper(child as VNode, wrapper, context), visitor);
}
}

Expand All @@ -91,10 +95,12 @@ function _virtualRender(depth: number, vnode: VNode, parent: VNode | null, conte
VNodeFlags.Connect
)) !== 0) {
if ((flags & VNodeFlags.Element) !== 0) {
let child = vnode._c;
while (child !== null) {
_virtualRender(depth, child, vnode, context);
child = child._r;
if ((flags & VNodeFlags.Children) !== 0) {
let child = vnode._c;
while (child !== null) {
_virtualRender(depth, child as VNode, vnode, context);
child = (child as VNode)._r;
}
}
} else {
if ((flags & (VNodeFlags.StatefulComponent | VNodeFlags.StatelessComponent)) !== 0) {
Expand All @@ -115,7 +121,7 @@ function _virtualRender(depth: number, vnode: VNode, parent: VNode | null, conte
}
}
if (depth > 1) {
return _virtualRender(depth - 1, vnode._c!, vnode, context);
return _virtualRender(depth - 1, vnode._c as VNode, vnode, context);
}
}
}
Expand All @@ -136,7 +142,7 @@ export class VNodeListWrapper {
}

filter(matcher: VNodeMatcher): VNodeListWrapper {
return new VNodeListWrapper(this.items.filter((i) => matcher.match(i)));
return new VNodeListWrapper(this.items.filter(i => matcher.match(i)));
}

forEach(fn: (n: VNodeWrapper, i: number) => void): void {
Expand Down Expand Up @@ -254,16 +260,15 @@ export class VNodeWrapper {
throw new Error("VNodeWrapper::getChildren() can only be called on element nodes");
}
const flags = this.vnode._f;
let children: VNodeWrapper[];
const children: VNodeWrapper[] = [];
if ((flags & VNodeFlags.Element) !== 0) {
children = [];
let child: VNode | null = this.vnode._c;
while (child !== null) {
children.push(new VNodeWrapper(child, this, this.context));
child = child._r;
if ((flags & VNodeFlags.Children) !== 0) {
let child = this.vnode._c as VNode | null;
while (child !== null) {
children.push(new VNodeWrapper(child, this, this.context));
child = child._r;
}
}
} else {
children = [];
}
return new VNodeListWrapper(children);
}
Expand Down Expand Up @@ -478,7 +483,7 @@ export function hasDirectParent(wrapper: VNodeWrapper, predicate: Predicate<VNod
}

export function hasChild(wrapper: VNodeWrapper, predicate: Predicate<VNodeWrapper>): boolean {
return visitWrapped(wrapper, (n) => (wrapper !== n && predicate(n)));
return visitWrapped(wrapper, n => (wrapper !== n && predicate(n)));
}

export function hasSibling(wrapper: VNodeWrapper, predicate: Predicate<VNodeWrapper>): boolean {
Expand Down Expand Up @@ -513,8 +518,7 @@ export function innerText(wrapper: VNodeWrapper): string {
visitUnwrapped(
wrapper.vnode,
wrapper.parent === null ? null : wrapper.parent.vnode,
wrapper.context,
(vnode) => {
wrapper.context, vnode => {
if ((vnode._f & VNodeFlags.Text) !== 0) {
result += vnode._c;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/ivi-tslint-rules/index.json
Expand Up @@ -64,6 +64,10 @@
"object-literal-shorthand": false,
"switch-default": false,
"variable-name": false,
"arrow-parens": [
true,
"ban-single-arg-parens"
],
"space-before-function-paren": [
true,
{
Expand Down
12 changes: 7 additions & 5 deletions packages/ivi/src/debug/html_nesting_rules.ts
Expand Up @@ -219,18 +219,20 @@ function visitNode(vnode: VNode, parentTagName: string, ancestorFlags: AncestorF

ancestorFlags |= ANCESTOR_FLAGS_BY_TAG_NAME[parentTagName];

let child = vnode._c;
while (child !== null) {
visitNode(child, parentTagName, ancestorFlags);
child = child._r;
if ((flags & VNodeFlags.Children) !== 0) {
let child = vnode._c as VNode | null;
while (child !== null) {
visitNode(child, parentTagName, ancestorFlags);
child = child._r;
}
}
} else if ((flags & (
VNodeFlags.StatelessComponent |
VNodeFlags.StatefulComponent |
VNodeFlags.Connect |
VNodeFlags.UpdateContext
)) !== 0) {
visitNode(vnode._c!, parentTagName, ancestorFlags);
visitNode(vnode._c as VNode, parentTagName, ancestorFlags);
}
}

Expand Down
22 changes: 15 additions & 7 deletions packages/ivi/src/events/accumulate_dispatch_targets.ts
Expand Up @@ -36,13 +36,21 @@ function visitUp(
if (parent !== root) {
vnode = visitUp(result, match, parent, root, vnode);

let child = vnode._c;
while (child !== null) {
const r = visitDown(result, match, element, child);
if (r) {
return r;
if ((vnode._f & (
VNodeFlags.Children |
VNodeFlags.StatelessComponent |
VNodeFlags.StatefulComponent |
VNodeFlags.Connect |
VNodeFlags.UpdateContext
)) !== 0) {
let child = vnode._c;
while (child !== null) {
const r = visitDown(result, match, element, child as VNode);
if (r) {
return r;
}
child = (child as VNode)._r;
}
child = child._r;
}
}

Expand All @@ -68,7 +76,7 @@ function visitDown(
VNodeFlags.Connect |
VNodeFlags.UpdateContext
)) {
r = visitDown(result, match, element, vnode._c!);
r = visitDown(result, match, element, vnode._c as VNode);
if (r) {
accumulateDispatchTargetsFromVNode(result, vnode, match);
return r;
Expand Down
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<div>""</div> 1`] = `<div />`;

exports[`<div>""</div> 2`] = `
Object {
"appendChild": 1,
"createElement": 2,
"createElementNS": 0,
"createTextNode": 0,
"insertBefore": 1,
"removeChild": 0,
"replaceChild": 0,
}
`;

exports[`<div>"abc"</div> 1`] = `
<div>
abc
</div>
`;

exports[`<div>"abc"</div> 2`] = `
Object {
"appendChild": 1,
"createElement": 2,
"createElementNS": 0,
"createTextNode": 0,
"insertBefore": 1,
"removeChild": 0,
"replaceChild": 0,
}
`;

exports[`<div>10</div> 1`] = `
<div>
10
</div>
`;

exports[`<div>10</div> 2`] = `
Object {
"appendChild": 1,
"createElement": 2,
"createElementNS": 0,
"createTextNode": 0,
"insertBefore": 1,
"removeChild": 0,
"replaceChild": 0,
}
`;
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<div>""</div> => <div>"abc"</div> 1`] = `
<div>
abc
</div>
`;

exports[`<div>"abc"</div> => <div>""</div> 1`] = `
<div>
</div>
`;

exports[`<div>"abc"</div> => <div>""</div> 2`] = `<div />`;

exports[`<div></div> => <div>"abc"</div> 1`] = `
<div>
abc
</div>
`;
10 changes: 5 additions & 5 deletions packages/ivi/src/vdom/__tests__/context.spec.ts
Expand Up @@ -3,16 +3,16 @@ import { startRender } from "./utils";

const Static = withShouldUpdate(
() => false,
statelessComponent<VNode>((child) => child),
statelessComponent<VNode>(child => child),
);

const ContextTestPrinterConnector = connect<{ value: string }, undefined, { value: string }>(
(prev, props, ctx) => ({ value: ctx.value }),
(props) => t(props.value),
props => t(props.value),
);

test(`<Context={ value: 10 }<Connector>{ ctx.value }</Connector></Context>`, () => {
startRender((r) => {
startRender(r => {
const v = (
context({ value: 10 },
ContextTestPrinterConnector(),
Expand All @@ -25,7 +25,7 @@ test(`<Context={ value: 10 }<Connector>{ ctx.value }</Connector></Context>`, ()
});

test(`Sync context value`, () => {
startRender((r) => {
startRender(r => {
const v1 = (
context({ value: 10 },
ContextTestPrinterConnector(),
Expand All @@ -44,7 +44,7 @@ test(`Sync context value`, () => {
});

test(`Sync context value inside component with shouldUpdate=false`, () => {
startRender((r) => {
startRender(r => {
const v1 = (
context({ value: 10 },
Static(
Expand Down

0 comments on commit b39555d

Please sign in to comment.