Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
perf(remax): 优化运行时性能
Browse files Browse the repository at this point in the history
  • Loading branch information
Darmody committed Feb 25, 2020
1 parent 1bff049 commit 43671d1
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 26 deletions.
113 changes: 89 additions & 24 deletions packages/remax/src/VNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ export type Path = Array<string | number>;
export default class VNode {
id: number;
container: Container;
children: VNode[];
mounted = false;
type: string;
props?: any;
parent: VNode | null = null;
firstChild: VNode | null = null;
lastChild: VNode | null = null;
size = 0;
previousSibling: VNode | null = null;
nextSibling: VNode | null = null;
text?: string;

constructor({
Expand All @@ -36,20 +40,49 @@ export default class VNode {
this.container = container;
this.type = type;
this.props = props;
this.children = [];
}

get index(): number {
if (!this.previousSibling) {
return 0;
}

return this.previousSibling.index + 1;
}

get children() {
const arr = [];
let item = this.firstChild;

while (item) {
arr.push(item);
item = item.nextSibling;
}

return arr;
}

appendChild(node: VNode, immediately: boolean) {
this.removeChild(node, immediately);
this.size += 1;

node.parent = this;
if (this.children.find(child => child.id === node.id)) {
this.removeChild(node, immediately);

if (!this.firstChild) {
this.firstChild = node;
}

this.children.push(node);
if (this.lastChild) {
this.lastChild.nextSibling = node;
node.previousSibling = this.lastChild;
}

this.lastChild = node;

if (this.isMounted()) {
this.container.requestUpdate(
[...this.path(), 'children'],
this.children.length - 1,
this.size - 1,
0,
immediately,
node.toJSON()
Expand All @@ -58,33 +91,68 @@ export default class VNode {
}

removeChild(node: VNode, immediately: boolean) {
const start = this.children.indexOf(node);
this.children.splice(start, 1);
const { previousSibling, nextSibling } = node;

if (node.parent !== this) {
return;
}

this.size -= 1;

if (this.firstChild === node) {
this.firstChild = node.nextSibling;
}

if (this.lastChild === node) {
this.lastChild = node.previousSibling;
}

if (previousSibling) {
previousSibling.nextSibling = nextSibling;
}

if (nextSibling) {
nextSibling.previousSibling = previousSibling;
}

node.previousSibling = null;
node.nextSibling = null;

if (this.isMounted()) {
this.container.requestUpdate(
[...this.path(), 'children'],
start,
node.index,
1,
immediately
);
}
}

insertBefore(newNode: VNode, referenceNode: VNode, immediately: boolean) {
newNode.parent = this;
if (this.children.find(child => child.id === newNode.id)) {
this.removeChild(newNode, immediately);
insertBefore(node: VNode, referenceNode: VNode, immediately: boolean) {
this.removeChild(node, immediately);
this.size += 1;

node.parent = this;

if (referenceNode === this.firstChild) {
this.firstChild = node;
}

if (referenceNode.previousSibling) {
referenceNode.previousSibling.nextSibling = node;
node.previousSibling = referenceNode.previousSibling;
}

const start = this.children.indexOf(referenceNode);
this.children.splice(start, 0, newNode);
referenceNode.previousSibling = node;
node.nextSibling = referenceNode;

if (this.isMounted()) {
this.container.requestUpdate(
[...this.path(), 'children'],
start,
referenceNode.index,
0,
immediately,
newNode.toJSON()
node.toJSON()
);
}
}
Expand All @@ -93,7 +161,7 @@ export default class VNode {
// root 不会更新,所以肯定有 parent
this.container.requestUpdate(
[...this.parent!.path(), 'children'],
this.parent!.children.indexOf(this),
this.index,
1,
false,
this.toJSON()
Expand All @@ -104,11 +172,7 @@ export default class VNode {
if (!this.parent) {
return ['root'];
}
return [
...this.parent.path(),
'children',
this.parent.children.indexOf(this),
];
return [...this.parent.path(), 'children', this.index];
}

isMounted(): boolean {
Expand All @@ -122,11 +186,12 @@ export default class VNode {
text: this.text,
};
}

return {
id: this.id,
type: this.type,
props: this.props,
children: this.children && this.children.map(c => c.toJSON()),
children: this.children.map(c => c.toJSON()),
text: this.text,
};
}
Expand Down
67 changes: 67 additions & 0 deletions packages/remax/src/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,73 @@ Object {
}
`;

exports[`remax render insert new element 3`] = `
Object {
"children": Array [
Object {
"children": Array [
Object {
"children": Array [
Object {
"text": "0",
"type": "plain-text",
},
],
"id": 9,
"props": Object {},
"text": undefined,
"type": "view",
},
Object {
"children": Array [
Object {
"text": "1",
"type": "plain-text",
},
],
"id": 2,
"props": Object {},
"text": undefined,
"type": "view",
},
Object {
"children": Array [
Object {
"text": "2",
"type": "plain-text",
},
],
"id": 7,
"props": Object {},
"text": undefined,
"type": "view",
},
Object {
"children": Array [
Object {
"text": "3",
"type": "plain-text",
},
],
"id": 4,
"props": Object {},
"text": undefined,
"type": "view",
},
],
"id": 5,
"props": Object {},
"text": undefined,
"type": "view",
},
],
"id": 0,
"props": undefined,
"text": undefined,
"type": "root",
}
`;

exports[`remax render render correctly 1`] = `
Object {
"children": Array [
Expand Down
12 changes: 10 additions & 2 deletions packages/remax/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,18 @@ describe('remax render', () => {
list: [1, 3],
};

update() {
insert() {
this.setState({
list: [1, 2, 3],
});
}

insertBefore() {
this.setState({
list: [0, 1, 2, 3],
});
}

render() {
const { list } = this.state;
return (
Expand All @@ -70,7 +76,9 @@ describe('remax render', () => {
const page = React.createRef<any>();
render(<Page ref={page} />, container);
expect(container.root).toMatchSnapshot();
page.current.update();
page.current.insert();
expect(container.root).toMatchSnapshot();
page.current.insertBefore();
expect(container.root).toMatchSnapshot();
});

Expand Down

0 comments on commit 43671d1

Please sign in to comment.