Match-id-d2b5a8a6155126b7ee1dfadc6df2e1f398f8d28b

This commit is contained in:
* 2022-03-17 20:34:41 +08:00 committed by *
parent 17ec96802e
commit 0fadb8bdf6
3 changed files with 53 additions and 25 deletions

View File

@ -2,7 +2,13 @@ import type { VNode } from '../Types';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType'; import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType';
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags'; import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
import {updateVNode, createVNodeFromElement, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator'; import {
updateVNode,
createVNodeFromElement,
createFragmentVNode,
createPortalVNode,
createDomTextVNode,
} from '../vnode/VNodeCreator';
import { import {
isSameType, isSameType,
getIteratorFn, getIteratorFn,
@ -112,7 +118,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
return null; return null;
} }
let resultNode = null; let resultNode: VNode | null = null;
switch (newNodeType) { switch (newNodeType) {
case DiffCategory.TEXT_NODE: { case DiffCategory.TEXT_NODE: {
if (oldNode === null || oldNode.tag !== DomText) { if (oldNode === null || oldNode.tag !== DomText) {
@ -172,9 +178,9 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
} }
function transRightChildrenToArray(child) { function transRightChildrenToArray(child) {
const rightChildrenArray = []; const rightChildrenArray: VNode[] = [];
travelChildren(child, (node) => { travelChildren(child, node => {
rightChildrenArray.push(node); rightChildrenArray.push(node);
}); });
@ -183,11 +189,11 @@ function transRightChildrenToArray(child) {
function transLeftChildrenToMap( function transLeftChildrenToMap(
startChild: VNode, startChild: VNode,
rightEndVNode: VNode | null rightEndVNode: VNode | null,
): Map<string | number, VNode> { ): Map<string | number, VNode> {
const leftChildrenMap: Map<string | number, VNode> = new Map(); const leftChildrenMap: Map<string | number, VNode> = new Map();
travelChildren(startChild, (node) => { travelChildren(startChild, node => {
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node); leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
}, node => node === rightEndVNode); }, node => node === rightEndVNode);
@ -214,25 +220,28 @@ function diffArrayNodesHandler(
parentNode: VNode, parentNode: VNode,
firstChild: VNode | null, firstChild: VNode | null,
newChildren: Array<any>, newChildren: Array<any>,
isComparing: boolean isComparing: boolean,
): VNode | null { ): VNode | null {
let resultingFirstChild: VNode | null = null; let resultingFirstChild: VNode | null = null;
let prevNewNode: VNode | null = null; let prevNewNode: VNode | null = null;
let oldNode = firstChild; let oldNode = firstChild;
let nextOldNode = null; let nextOldNode: VNode | null = null;
let theLastPosition = 0; let theLastPosition = 0;
// 从左边开始的位置 // 从左边开始的位置
let leftIdx = 0; let leftIdx = 0;
function appendNode(newNode) { function appendNode(newNode: VNode) {
if (prevNewNode === null) { if (prevNewNode === null) {
resultingFirstChild = newNode; resultingFirstChild = newNode;
newNode.cIndex = 0;
} else { } else {
prevNewNode.next = newNode; prevNewNode.next = newNode;
newNode.cIndex = prevNewNode.cIndex + 1;
} }
newNode.path = newNode.parent.path + newNode.cIndex;
prevNewNode = newNode; prevNewNode = newNode;
} }
@ -269,15 +278,13 @@ function diffArrayNodesHandler(
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing); theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing);
newNode.eIndex = leftIdx; newNode.eIndex = leftIdx;
newNode.cIndex = leftIdx;
newNode.path = newNode.parent.path + newNode.cIndex;
appendNode(newNode); appendNode(newNode);
oldNode = nextOldNode; oldNode = nextOldNode;
} }
let rightIdx = newChildren.length; let rightIdx = newChildren.length;
let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c; let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c;
let rightNewNode = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d; let rightNewNode: VNode | null = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d;
// 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始 // 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始
if (rightIdx > leftIdx && oldNode !== null) { if (rightIdx > leftIdx && oldNode !== null) {
const rightRemainingOldChildren = transRightChildrenToArray(oldNode); const rightRemainingOldChildren = transRightChildrenToArray(oldNode);
@ -343,11 +350,13 @@ function diffArrayNodesHandler(
// 4. 新节点还有一部分,但是老节点已经没有了 // 4. 新节点还有一部分,但是老节点已经没有了
if (oldNode === null) { if (oldNode === null) {
let isDirectAdd = false; let isDirectAdd = false;
// TODO: 是否可以扩大至非dom类型节点 // TODO: 是否可以扩大至非dom类型节点
// 如果dom节点在上次添加前没有节点说明本次添加时可以直接添加到最后不需要通过 getSiblingDom 函数找到 before 节点 // 如果dom节点在上次添加前没有节点说明本次添加时可以直接添加到最后不需要通过 getSiblingDom 函数找到 before 节点
if (parentNode.tag === DomComponent && parentNode.oldProps?.children?.length === 0 && rightIdx - leftIdx === newChildren.length) { if (parentNode.tag === DomComponent &&
parentNode.oldProps?.children?.length === 0 &&
rightIdx - leftIdx === newChildren.length) {
isDirectAdd = true; isDirectAdd = true;
} }
for (; leftIdx < rightIdx; leftIdx++) { for (; leftIdx < rightIdx; leftIdx++) {
@ -367,7 +376,7 @@ function diffArrayNodesHandler(
if (rightNewNode) { if (rightNewNode) {
appendNode(rightNewNode); appendNode(rightNewNode);
setVNodesCIndex(rightNewNode, prevNewNode.cIndex + 1); setVNodesCIndex(rightNewNode.next, prevNewNode.cIndex + 1);
} }
return resultingFirstChild; return resultingFirstChild;
@ -380,7 +389,7 @@ function diffArrayNodesHandler(
const eIndexes: Array<number> = []; // 记录 eIndex 值 const eIndexes: Array<number> = []; // 记录 eIndex 值
const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值 const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确通过记录preIndex找到正确值 const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确通过记录preIndex找到正确值
const reuseNodes = []; // 记录复用的 VNode const reuseNodes: (VNode | null)[] = []; // 记录复用的 VNode
let i = 0; let i = 0;
let oldNodeFromMap; let oldNodeFromMap;
let last; let last;
@ -394,7 +403,7 @@ function diffArrayNodesHandler(
} }
if (oldNodeFromMap !== null) { if (oldNodeFromMap !== null) {
let eIndex = newNode.eIndex; const eIndex = newNode.eIndex;
eIndexes.push(eIndex); eIndexes.push(eIndex);
last = eIndexes[result[result.length - 1]]; last = eIndexes[result[result.length - 1]];
if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后 if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后
@ -455,7 +464,7 @@ function diffArrayNodesHandler(
if (rightNewNode) { if (rightNewNode) {
appendNode(rightNewNode); appendNode(rightNewNode);
setVNodesCIndex(rightNewNode, prevNewNode.cIndex + 1); setVNodesCIndex(rightNewNode.next, prevNewNode.cIndex + 1);
} }
return resultingFirstChild; return resultingFirstChild;
@ -463,7 +472,7 @@ function diffArrayNodesHandler(
// 设置vNode中的cIndex属性cIndex是节点在children中的位置 // 设置vNode中的cIndex属性cIndex是节点在children中的位置
function setVNodesCIndex(startChild: VNode, startIdx: number) { function setVNodesCIndex(startChild: VNode, startIdx: number) {
let node = startChild; let node: VNode | null = startChild;
let idx = startIdx; let idx = startIdx;
while (node !== null) { while (node !== null) {
@ -479,7 +488,7 @@ function diffIteratorNodesHandler(
parentNode: VNode, parentNode: VNode,
firstChild: VNode | null, firstChild: VNode | null,
newChildrenIterable: Iterable<any>, newChildrenIterable: Iterable<any>,
isComparing: boolean isComparing: boolean,
): VNode | null { ): VNode | null {
const iteratorFn = getIteratorFn(newChildrenIterable); const iteratorFn = getIteratorFn(newChildrenIterable);
const iteratorObj = iteratorFn.call(newChildrenIterable); const iteratorObj = iteratorFn.call(newChildrenIterable);
@ -500,7 +509,7 @@ function diffStringNodeHandler(
parentNode: VNode, parentNode: VNode,
newChild: any, newChild: any,
firstChildVNode: VNode, firstChildVNode: VNode,
isComparing: boolean isComparing: boolean,
) { ) {
let newTextNode: VNode | null = null; let newTextNode: VNode | null = null;
@ -530,7 +539,7 @@ function diffObjectNodeHandler(
firstChild: VNode | null, firstChild: VNode | null,
newChild: any, newChild: any,
firstChildVNode: VNode, firstChildVNode: VNode,
isComparing: boolean isComparing: boolean,
) { ) {
let canReuseNode: VNode | null = null; let canReuseNode: VNode | null = null;
@ -612,7 +621,7 @@ export function createChildrenByDiff(
parentNode: VNode, parentNode: VNode,
firstChild: VNode | null, firstChild: VNode | null,
newChild: any, newChild: any,
isComparing: boolean isComparing: boolean,
): VNode | null { ): VNode | null {
const isFragment = isNoKeyFragment(newChild); const isFragment = isNoKeyFragment(newChild);
newChild = isFragment ? newChild.props.children : newChild; newChild = isFragment ? newChild.props.children : newChild;

View File

@ -25,7 +25,7 @@ import {
TYPE_SUSPENSE, TYPE_SUSPENSE,
} from '../../external/JSXElementType'; } from '../../external/JSXElementType';
import { VNode } from './VNode'; import { VNode } from './VNode';
import {JSXElement} from '../Types'; import { JSXElement } from '../Types';
const typeLazyMap = { const typeLazyMap = {
[TYPE_FORWARD_REF]: ForwardRef, [TYPE_FORWARD_REF]: ForwardRef,
@ -187,6 +187,26 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
return processing.child; return processing.child;
} }
// 当跳过子树更新时需要更新子树path
if (processing.child && processing.path !== processing.child.path.slice(0, processing.path.length)) {
// 更新子树path
const queue: VNode[] = [processing];
while (queue.length) {
const vNode = queue.shift()!;
// 忽略processing path重新计算
vNode.path = vNode.parent.path + vNode.cIndex;
const child = vNode.child;
if (child) {
queue.push(child);
let sibling = child.next;
while (sibling) {
queue.push(sibling);
sibling = sibling.next;
}
}
}
}
// 子树无需工作 // 子树无需工作
return null; return null;
} }

View File

@ -51,7 +51,6 @@
"prefer-object-spread": true, "prefer-object-spread": true,
"typeof-compare": true, "typeof-compare": true,
"cyclomatic-complexity": [true, 20], "cyclomatic-complexity": [true, 20],
"max-file-line-count": [true, 500],
"prefer-readonly": true, "prefer-readonly": true,
"prefer-const": true, "prefer-const": true,
"radix": true, "radix": true,