Match-id-31567eb282df128107bb6505da5382c789b75783
This commit is contained in:
commit
25ecaa0c71
|
@ -81,7 +81,7 @@ function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
||||||
if (parent.dirtyNodes === null) {
|
if (parent.dirtyNodes === null) {
|
||||||
parent.dirtyNodes = dirtyNodes;
|
parent.dirtyNodes = dirtyNodes;
|
||||||
} else {
|
} else {
|
||||||
parent.dirtyNodes.push(...dirtyNodes);
|
parent.dirtyNodes.push(...vNode.dirtyNodes);
|
||||||
dirtyNodes.length = 0;
|
dirtyNodes.length = 0;
|
||||||
}
|
}
|
||||||
vNode.dirtyNodes = null;
|
vNode.dirtyNodes = null;
|
||||||
|
@ -100,7 +100,7 @@ function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
||||||
|
|
||||||
// 尝试完成当前工作单元,然后移动到下一个兄弟工作单元。如果没有更多的同级,请返回父vNode。
|
// 尝试完成当前工作单元,然后移动到下一个兄弟工作单元。如果没有更多的同级,请返回父vNode。
|
||||||
function bubbleVNode(vNode: VNode): void {
|
function bubbleVNode(vNode: VNode): void {
|
||||||
let node: VNode | null = vNode;
|
let node = vNode;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const parent = node.parent;
|
const parent = node.parent;
|
||||||
|
@ -179,18 +179,14 @@ function isEqualByIndex(idx: number, pathArrays: string[][]) {
|
||||||
function getChildByIndex(vNode: VNode, idx: number) {
|
function getChildByIndex(vNode: VNode, idx: number) {
|
||||||
let node = vNode.child;
|
let node = vNode.child;
|
||||||
for (let i = 0; i < idx; i++) {
|
for (let i = 0; i < idx; i++) {
|
||||||
if (node !== null) {
|
node = node.next;
|
||||||
node = node.next;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
||||||
export function calcStartUpdateVNode(treeRoot: VNode) {
|
export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||||
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes!);
|
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
|
||||||
|
|
||||||
if (toUpdateNodes.length === 0) {
|
if (toUpdateNodes.length === 0) {
|
||||||
return treeRoot;
|
return treeRoot;
|
||||||
|
@ -219,12 +215,12 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||||
// 得到相等的路径
|
// 得到相等的路径
|
||||||
const startNodePath = pathArrays[0].slice(0, commonPathEndIndex);
|
const startNodePath = pathArrays[0].slice(0, commonPathEndIndex);
|
||||||
|
|
||||||
let node: VNode | null = treeRoot;
|
let node = treeRoot;
|
||||||
for (let i = 1; i < startNodePath.length; i++) {
|
for (let i = 1; i < startNodePath.length; i++) {
|
||||||
const pathIndex = Number(startNodePath[i]);
|
const pathIndex = Number(startNodePath[i]);
|
||||||
node = getChildByIndex(node, pathIndex);
|
node = getChildByIndex(node, pathIndex)!;
|
||||||
// 路径错误时,回退到从根更新
|
// 路径错误时,回退到从根更新
|
||||||
if (node === null) {
|
if (node == null) {
|
||||||
return treeRoot;
|
return treeRoot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +239,7 @@ function buildVNodeTree(treeRoot: VNode) {
|
||||||
setStartVNode(startVNode);
|
setStartVNode(startVNode);
|
||||||
|
|
||||||
// 清空toUpdateNodes
|
// 清空toUpdateNodes
|
||||||
treeRoot.toUpdateNodes!.clear();
|
treeRoot.toUpdateNodes.clear();
|
||||||
|
|
||||||
if (startVNode.tag !== TreeRoot) {
|
if (startVNode.tag !== TreeRoot) {
|
||||||
// 不是根节点
|
// 不是根节点
|
||||||
|
@ -351,10 +347,16 @@ function renderFromRoot(treeRoot) {
|
||||||
// 2. 提交变更
|
// 2. 提交变更
|
||||||
submitToRender(treeRoot);
|
submitToRender(treeRoot);
|
||||||
popCurrentRoot();
|
popCurrentRoot();
|
||||||
|
if (window.__HORIZON_DEV_HOOK__) {
|
||||||
// 与Devtool通信
|
const hook = window.__HORIZON_DEV_HOOK__;
|
||||||
sendRootToDevTool(treeRoot);
|
// injector.js 可能在 Horizon 代码之后加载,此时无 __HORIZON_DEV_HOOK__ 全局变量
|
||||||
|
// Horizon 代码初次加载时不会初始化 helper
|
||||||
|
if (!hook.isInit) {
|
||||||
|
injectUpdater();
|
||||||
|
}
|
||||||
|
hook.addIfNotInclude(treeRoot);
|
||||||
|
hook.send(treeRoot);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,25 +403,6 @@ export function launchUpdateFromVNode(vNode: VNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
__HORIZON_DEV_HOOK__: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendRootToDevTool(treeRoot) {
|
|
||||||
if (window.__HORIZON_DEV_HOOK__) {
|
|
||||||
const hook = window.__HORIZON_DEV_HOOK__;
|
|
||||||
// injector.js 可能在 Horizon 代码之后加载,此时无 __HORIZON_DEV_HOOK__ 全局变量
|
|
||||||
// Horizon 代码初次加载时不会初始化 helper
|
|
||||||
if (!hook.isInit) {
|
|
||||||
injectUpdater();
|
|
||||||
}
|
|
||||||
hook.addIfNotInclude(treeRoot);
|
|
||||||
hook.send(treeRoot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== HorizonDOM使用 ==============================
|
// ============================== HorizonDOM使用 ==============================
|
||||||
export function runDiscreteUpdates() {
|
export function runDiscreteUpdates() {
|
||||||
if (checkMode(ByAsync) || checkMode(InRender)) {
|
if (checkMode(ByAsync) || checkMode(InRender)) {
|
||||||
|
|
|
@ -34,13 +34,6 @@ enum DiffCategory {
|
||||||
ARR_NODE = 'ARR_NODE',
|
ARR_NODE = 'ARR_NODE',
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppendVNode = (vnode: VNode) => void;
|
|
||||||
interface DiffRightSideResult {
|
|
||||||
rightIdx: number;
|
|
||||||
rightEndOldNode: VNode;
|
|
||||||
rightNewNode: VNode | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是不是被 FRAGMENT 包裹
|
// 检查是不是被 FRAGMENT 包裹
|
||||||
function isNoKeyFragment(child: any) {
|
function isNoKeyFragment(child: any) {
|
||||||
return child != null && child.type === TYPE_FRAGMENT && child.key === null;
|
return child != null && child.type === TYPE_FRAGMENT && child.key === null;
|
||||||
|
@ -118,12 +111,19 @@ function getNodeType(newChild: any): string | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置vNode的flag
|
// 设置vNode的flag
|
||||||
function setVNodeAdditionFlag(newNode: VNode) {
|
function setVNodeAdditionFlag(newNode: VNode, lastPosition: number): number {
|
||||||
if (newNode.isCreated) {
|
let position = lastPosition;
|
||||||
|
|
||||||
|
if (newNode.isCreated || newNode.eIndex < lastPosition) {
|
||||||
// 位置 小于 上一个复用的位置
|
// 位置 小于 上一个复用的位置
|
||||||
// 标记为新增
|
// 标记为新增
|
||||||
FlagUtils.setAddition(newNode);
|
FlagUtils.setAddition(newNode);
|
||||||
|
} else {
|
||||||
|
// 复用
|
||||||
|
position = newNode.eIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取新节点
|
// 获取新节点
|
||||||
|
@ -231,75 +231,74 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// diff数组类型的节点,核心算法
|
||||||
* 左端新老节点对比
|
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
|
||||||
* @param firstNode 第一个VNode
|
let resultingFirstChild: VNode | null = null;
|
||||||
* @param newChildren 新的JSX children
|
|
||||||
* @param parentNode 父节点
|
let prevNewNode: VNode | null = null;
|
||||||
* @param appendNode 添加节点
|
|
||||||
*/
|
let oldNode = firstChild;
|
||||||
function diffLeftSide(firstNode: VNode | null, newChildren: Array<any>, parentNode: VNode, appendNode: AppendVNode) {
|
|
||||||
let nextOldNode: VNode | null = null;
|
let nextOldNode: VNode | null = null;
|
||||||
|
|
||||||
|
let theLastPosition = 0;
|
||||||
// 从左边开始的位置
|
// 从左边开始的位置
|
||||||
let leftIdx = 0;
|
let leftIdx = 0;
|
||||||
// 1. 从左侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
|
||||||
for (; firstNode !== null && leftIdx < newChildren.length; leftIdx++) {
|
function appendNode(newNode: VNode) {
|
||||||
if (firstNode.eIndex > leftIdx) {
|
if (prevNewNode === null) {
|
||||||
// 当新旧节点位置不一,则将缓存当前的旧节点,放到下一次对比
|
resultingFirstChild = newNode;
|
||||||
nextOldNode = firstNode;
|
newNode.cIndex = 0;
|
||||||
firstNode = null;
|
|
||||||
} else {
|
} else {
|
||||||
nextOldNode = firstNode.next;
|
prevNewNode.next = newNode;
|
||||||
|
newNode.cIndex = prevNewNode.cIndex + 1;
|
||||||
|
}
|
||||||
|
markVNodePath(newNode);
|
||||||
|
prevNewNode = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let canBeReuse;
|
||||||
|
let newNode;
|
||||||
|
// 1. 从左侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
||||||
|
for (; oldNode !== null && leftIdx < newChildren.length; leftIdx++) {
|
||||||
|
if (oldNode.eIndex > leftIdx) {
|
||||||
|
// 当新旧节点位置不一,则将缓存当前的旧节点,放到下一次对比
|
||||||
|
nextOldNode = oldNode;
|
||||||
|
oldNode = null;
|
||||||
|
} else {
|
||||||
|
nextOldNode = oldNode.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx], leftIdx);
|
||||||
// 不能复用,break
|
// 不能复用,break
|
||||||
if (!checkCanReuseNode(firstNode, newChildren[leftIdx], leftIdx)) {
|
if (!canBeReuse) {
|
||||||
firstNode = firstNode ?? nextOldNode;
|
oldNode = oldNode ?? nextOldNode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], firstNode);
|
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNode);
|
||||||
// 没有生成新节点,break
|
// 没有生成新节点,break
|
||||||
if (!newNode) {
|
if (!newNode) {
|
||||||
firstNode = firstNode ?? nextOldNode;
|
oldNode = oldNode ?? nextOldNode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff过程中,需要将现有的节点清除掉,如果是创建,则不需要处理(因为没有现存节点)
|
// diff过程中,需要将现有的节点清除掉,如果是创建,则不需要处理(因为没有现存节点)
|
||||||
if (firstNode && newNode.isCreated) {
|
if (oldNode && newNode.isCreated) {
|
||||||
deleteVNode(parentNode, firstNode);
|
deleteVNode(parentNode, oldNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
setVNodeAdditionFlag(newNode);
|
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition);
|
||||||
newNode.eIndex = leftIdx;
|
newNode.eIndex = leftIdx;
|
||||||
appendNode(newNode);
|
appendNode(newNode);
|
||||||
firstNode = nextOldNode;
|
oldNode = nextOldNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { leftEndOldNode: firstNode, leftIdx };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 右端新老节点对比
|
|
||||||
* @param leftEndOldNode 左端对比完成后第一个不同的老节点
|
|
||||||
* @param leftIdx 左端diff完成后Index
|
|
||||||
* @param newChildren 新的JSX children
|
|
||||||
* @param parentNode 父节点
|
|
||||||
*/
|
|
||||||
function diffRightSide(
|
|
||||||
leftEndOldNode: VNode | null,
|
|
||||||
leftIdx: number,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
parentNode: VNode
|
|
||||||
): DiffRightSideResult {
|
|
||||||
let newNode;
|
|
||||||
let canBeReuse = false;
|
|
||||||
let rightIdx = newChildren.length;
|
let rightIdx = newChildren.length;
|
||||||
let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c;
|
let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c;
|
||||||
let rightNewNode: VNode | null = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d;
|
let rightNewNode: VNode | null = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d;
|
||||||
// 从后往前,新资源的位置还没有到最末端,旧的vNode也还没遍历完,则可以考虑从后往前开始
|
// 从后往前,新资源的位置还没有到最末端,旧的vNode也还没遍历完,则可以考虑从后往前开始
|
||||||
if (rightIdx > leftIdx && leftEndOldNode !== null) {
|
if (rightIdx > leftIdx && oldNode !== null) {
|
||||||
const rightRemainingOldChildren = transRightChildrenToArray(leftEndOldNode);
|
const rightRemainingOldChildren = transRightChildrenToArray(oldNode);
|
||||||
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
|
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
|
||||||
|
|
||||||
// 2. 从右侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
// 2. 从右侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
||||||
|
@ -334,125 +333,72 @@ function diffRightSide(
|
||||||
deleteVNode(parentNode, rightOldNode);
|
deleteVNode(parentNode, rightOldNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
setVNodeAdditionFlag(newNode);
|
setVNodeAdditionFlag(newNode, theLastPosition);
|
||||||
newNode.eIndex = rightIdx - 1;
|
newNode.eIndex = rightIdx - 1;
|
||||||
rightOldIndex--;
|
rightOldIndex--;
|
||||||
rightEndOldNode = rightOldNode;
|
rightEndOldNode = rightOldNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { rightIdx, rightEndOldNode, rightNewNode };
|
// 3. 新节点已经处理完成
|
||||||
}
|
if (leftIdx === rightIdx) {
|
||||||
|
if (firstChild && parentNode.tag === DomComponent && newChildren.length === 0) {
|
||||||
/**
|
FlagUtils.markClear(parentNode);
|
||||||
* 添加所有右端Diff完成的节点
|
parentNode.clearChild = firstChild;
|
||||||
* @param leftEndOldNode 左端对比完成后第一个不同的老节点
|
} else {
|
||||||
* @param parentNode 父节点
|
deleteVNodes(parentNode, oldNode, rightEndOldNode);
|
||||||
* @param firstChild 第一个VNode
|
|
||||||
* @param newChildren 新的JSX children
|
|
||||||
* @param diffRightSideResult 右端diff结果
|
|
||||||
* @param appendNode 添加节点
|
|
||||||
*/
|
|
||||||
function appendRightSideNode(
|
|
||||||
leftEndOldNode: VNode | null,
|
|
||||||
parentNode: VNode,
|
|
||||||
firstChild: VNode | null,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
diffRightSideResult: DiffRightSideResult,
|
|
||||||
appendNode: AppendVNode
|
|
||||||
) {
|
|
||||||
const { rightEndOldNode, rightNewNode } = diffRightSideResult;
|
|
||||||
|
|
||||||
// 清除中间残留的节点
|
|
||||||
if (firstChild && parentNode.tag === DomComponent && newChildren.length === 0) {
|
|
||||||
FlagUtils.markClear(parentNode);
|
|
||||||
parentNode.clearChild = firstChild;
|
|
||||||
} else {
|
|
||||||
deleteVNodes(parentNode, leftEndOldNode, rightEndOldNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rightNewNode) {
|
|
||||||
appendNode(rightNewNode);
|
|
||||||
setVNodesCIndex(rightNewNode, rightNewNode.cIndex + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加左右端比较完成后剩余新节点和右侧节点
|
|
||||||
* @param leftEndOldNode 左端对比完成后第一个不同的老节点
|
|
||||||
* @param parentNode 父节点
|
|
||||||
* @param newChildren 新的JSX children
|
|
||||||
* @param leftIdx 左端diff完成后Index
|
|
||||||
* @param diffRightSideResult 右端diff结果
|
|
||||||
* @param appendNode 添加节点
|
|
||||||
*/
|
|
||||||
function appendAllRestNode(
|
|
||||||
leftEndOldNode: VNode | null,
|
|
||||||
parentNode: VNode,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
leftIdx: number,
|
|
||||||
diffRightSideResult: DiffRightSideResult,
|
|
||||||
appendNode: AppendVNode
|
|
||||||
) {
|
|
||||||
let isDirectAdd = false;
|
|
||||||
const { rightIdx, rightNewNode } = diffRightSideResult;
|
|
||||||
|
|
||||||
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
|
||||||
if (
|
|
||||||
parentNode.tag === DomComponent &&
|
|
||||||
parentNode.oldProps?.children?.length === 0 &&
|
|
||||||
rightIdx - leftIdx === newChildren.length
|
|
||||||
) {
|
|
||||||
isDirectAdd = true;
|
|
||||||
}
|
|
||||||
const isAddition = parentNode.tag === DomPortal || !parentNode.isCreated;
|
|
||||||
for (; leftIdx < rightIdx; leftIdx++) {
|
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], null);
|
|
||||||
|
|
||||||
if (newNode !== null) {
|
|
||||||
if (isAddition) {
|
|
||||||
FlagUtils.setAddition(newNode);
|
|
||||||
}
|
|
||||||
if (isDirectAdd) {
|
|
||||||
FlagUtils.markDirectAddition(newNode);
|
|
||||||
}
|
|
||||||
newNode.eIndex = leftIdx;
|
|
||||||
appendNode(newNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rightNewNode) {
|
||||||
|
appendNode(rightNewNode);
|
||||||
|
setVNodesCIndex(rightNewNode, prevNewNode.cIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultingFirstChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightNewNode) {
|
// 4. 新节点还有一部分,但是老节点已经没有了
|
||||||
appendNode(rightNewNode);
|
if (oldNode === null) {
|
||||||
setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
|
let isDirectAdd = false;
|
||||||
|
// TODO: 是否可以扩大至非dom类型节点
|
||||||
|
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
||||||
|
if (
|
||||||
|
parentNode.tag === DomComponent &&
|
||||||
|
parentNode.oldProps?.children?.length === 0 &&
|
||||||
|
rightIdx - leftIdx === newChildren.length
|
||||||
|
) {
|
||||||
|
isDirectAdd = true;
|
||||||
|
}
|
||||||
|
const isAddition = parentNode.tag === DomPortal || !parentNode.isCreated;
|
||||||
|
for (; leftIdx < rightIdx; leftIdx++) {
|
||||||
|
newNode = getNewNode(parentNode, newChildren[leftIdx], null);
|
||||||
|
|
||||||
|
if (newNode !== null) {
|
||||||
|
if (isAddition) {
|
||||||
|
FlagUtils.setAddition(newNode);
|
||||||
|
}
|
||||||
|
if (isDirectAdd) {
|
||||||
|
FlagUtils.markDirectAddition(newNode);
|
||||||
|
}
|
||||||
|
newNode.eIndex = leftIdx;
|
||||||
|
appendNode(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightNewNode) {
|
||||||
|
appendNode(rightNewNode);
|
||||||
|
setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultingFirstChild;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 双端对比完成,新老节点都有剩余时,构造LIS(最长递增子序列)
|
|
||||||
* 属于LIS的新节点直接复用,否则新增
|
|
||||||
* @param leftEndOldNode 左端对比完成后第一个不同的老节点
|
|
||||||
* @param parentNode 父节点
|
|
||||||
* @param newChildren 新的JSX children
|
|
||||||
* @param leftIdx 左端diff完成后Index
|
|
||||||
* @param diffRightSideResult 右端diff结果
|
|
||||||
* @param appendNode 添加节点
|
|
||||||
*/
|
|
||||||
function appendNodeWithLIS(
|
|
||||||
leftEndOldNode: VNode,
|
|
||||||
parentNode: VNode,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
leftIdx: number,
|
|
||||||
diffRightSideResult: DiffRightSideResult,
|
|
||||||
appendNode: AppendVNode
|
|
||||||
) {
|
|
||||||
const { rightIdx, rightNewNode, rightEndOldNode } = diffRightSideResult;
|
|
||||||
|
|
||||||
|
// 5. 新节点还有一部分,但是老节点也还有一部分
|
||||||
// 把剩下的currentVNode转成Map
|
// 把剩下的currentVNode转成Map
|
||||||
const leftChildrenMap = transLeftChildrenToMap(leftEndOldNode, rightEndOldNode);
|
const leftChildrenMap = transLeftChildrenToMap(oldNode, rightEndOldNode);
|
||||||
// 通过贪心算法+二分法获取最长递增子序列
|
// 通过贪心算法+二分法获取最长递增子序列
|
||||||
const eIndexes: Array<number> = []; // 记录 eIndex 值
|
const eIndexes: Array<number> = []; // 记录 eIndex 值
|
||||||
const subsequence: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值
|
const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值
|
||||||
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
||||||
const reuseNodes: (VNode | null)[] = []; // 记录复用的 VNode
|
const reuseNodes: (VNode | null)[] = []; // 记录复用的 VNode
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
@ -460,7 +406,7 @@ function appendNodeWithLIS(
|
||||||
let last;
|
let last;
|
||||||
for (; leftIdx < rightIdx; leftIdx++) {
|
for (; leftIdx < rightIdx; leftIdx++) {
|
||||||
oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
|
oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
|
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
|
||||||
if (newNode !== null) {
|
if (newNode !== null) {
|
||||||
if (newNode.isCreated) {
|
if (newNode.isCreated) {
|
||||||
// 新VNode,直接打上标签新增,不参与到复用,旧的VNode会在后面打上delete标签
|
// 新VNode,直接打上标签新增,不参与到复用,旧的VNode会在后面打上delete标签
|
||||||
|
@ -471,27 +417,27 @@ function appendNodeWithLIS(
|
||||||
if (oldNodeFromMap !== null) {
|
if (oldNodeFromMap !== null) {
|
||||||
const eIndex = newNode.eIndex;
|
const eIndex = newNode.eIndex;
|
||||||
eIndexes.push(eIndex);
|
eIndexes.push(eIndex);
|
||||||
last = eIndexes[subsequence[subsequence.length - 1]];
|
last = eIndexes[result[result.length - 1]];
|
||||||
if (eIndex > last || last === undefined) {
|
if (eIndex > last || last === undefined) {
|
||||||
// 大的 eIndex直接放在最后
|
// 大的 eIndex直接放在最后
|
||||||
preIndex[i] = subsequence[subsequence.length - 1];
|
preIndex[i] = result[result.length - 1];
|
||||||
subsequence.push(i);
|
result.push(i);
|
||||||
} else {
|
} else {
|
||||||
let start = 0;
|
let start = 0;
|
||||||
let end = subsequence.length - 1;
|
let end = result.length - 1;
|
||||||
let middle;
|
let middle;
|
||||||
// 二分法找到需要替换的值
|
// 二分法找到需要替换的值
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
middle = Math.floor((start + end) / 2);
|
middle = Math.floor((start + end) / 2);
|
||||||
if (eIndexes[subsequence[middle]] > eIndex) {
|
if (eIndexes[result[middle]] > eIndex) {
|
||||||
end = middle;
|
end = middle;
|
||||||
} else {
|
} else {
|
||||||
start = middle + 1;
|
start = middle + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eIndex < eIndexes[subsequence[start]]) {
|
if (eIndex < eIndexes[result[start]]) {
|
||||||
preIndex[i] = subsequence[start - 1];
|
preIndex[i] = result[start - 1];
|
||||||
subsequence[start] = i;
|
result[start] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
@ -504,13 +450,13 @@ function appendNodeWithLIS(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向前回溯找到正确的结果
|
// 向前回溯找到正确的结果
|
||||||
let length = subsequence.length;
|
let length = result.length;
|
||||||
let prev = subsequence[length - 1];
|
let prev = result[length - 1];
|
||||||
while (length-- > 0) {
|
while (length-- > 0) {
|
||||||
subsequence[length] = prev;
|
result[length] = prev;
|
||||||
prev = preIndex[subsequence[length]];
|
prev = preIndex[result[length]];
|
||||||
}
|
}
|
||||||
subsequence.forEach(idx => {
|
result.forEach(idx => {
|
||||||
// 把需要复用的节点从 restNodes 中清理掉,因为不需要打 add 标记,直接复用 dom 节点
|
// 把需要复用的节点从 restNodes 中清理掉,因为不需要打 add 标记,直接复用 dom 节点
|
||||||
reuseNodes[idx] = null;
|
reuseNodes[idx] = null;
|
||||||
});
|
});
|
||||||
|
@ -528,45 +474,7 @@ function appendNodeWithLIS(
|
||||||
appendNode(rightNewNode);
|
appendNode(rightNewNode);
|
||||||
setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
|
setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// diff数组类型的节点,核心算法
|
|
||||||
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
|
|
||||||
let resultingFirstChild: VNode | null = null;
|
|
||||||
let prevNewNode: VNode | null = null;
|
|
||||||
|
|
||||||
function appendNode(newNode: VNode) {
|
|
||||||
if (prevNewNode === null) {
|
|
||||||
resultingFirstChild = newNode;
|
|
||||||
newNode.cIndex = 0;
|
|
||||||
} else {
|
|
||||||
prevNewNode.next = newNode;
|
|
||||||
newNode.cIndex = prevNewNode.cIndex + 1;
|
|
||||||
}
|
|
||||||
markVNodePath(newNode);
|
|
||||||
prevNewNode = newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 左端新老节点对比
|
|
||||||
const { leftEndOldNode, leftIdx } = diffLeftSide(firstChild, newChildren, parentNode, appendNode);
|
|
||||||
|
|
||||||
// 2. 右端新老节点对比
|
|
||||||
const diffRightSideResult = diffRightSide(leftEndOldNode, leftIdx, newChildren, parentNode);
|
|
||||||
|
|
||||||
// 3. 新节点已经处理完成
|
|
||||||
if (leftIdx === diffRightSideResult.rightIdx) {
|
|
||||||
appendRightSideNode(leftEndOldNode, parentNode, firstChild, newChildren, diffRightSideResult, appendNode);
|
|
||||||
return resultingFirstChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 新节点还有一部分,但是老节点已经没有了
|
|
||||||
if (leftEndOldNode === null) {
|
|
||||||
appendAllRestNode(leftEndOldNode, parentNode, newChildren, leftIdx, diffRightSideResult, appendNode);
|
|
||||||
return resultingFirstChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. 新节点还有一部分,但是老节点也还有一部分
|
|
||||||
appendNodeWithLIS(leftEndOldNode, parentNode, newChildren, leftIdx, diffRightSideResult, appendNode);
|
|
||||||
return resultingFirstChild;
|
return resultingFirstChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,10 +498,10 @@ function diffIteratorNodesHandler(
|
||||||
newChildrenIterable: Iterable<any>
|
newChildrenIterable: Iterable<any>
|
||||||
): VNode | null {
|
): VNode | null {
|
||||||
const iteratorFn = getIteratorFn(newChildrenIterable);
|
const iteratorFn = getIteratorFn(newChildrenIterable);
|
||||||
const iteratorObj: Iterator<any> = iteratorFn.call(newChildrenIterable);
|
const iteratorObj = iteratorFn.call(newChildrenIterable);
|
||||||
|
|
||||||
// 把iterator转测数组
|
// 把iterator转测数组
|
||||||
const childrenArray: any[] = [];
|
const childrenArray = [];
|
||||||
let result = iteratorObj.next();
|
let result = iteratorObj.next();
|
||||||
while (!result.done) {
|
while (!result.done) {
|
||||||
childrenArray.push(result.value);
|
childrenArray.push(result.value);
|
||||||
|
@ -604,7 +512,7 @@ function diffIteratorNodesHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新节点是字符串类型
|
// 新节点是字符串类型
|
||||||
function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode: VNode | null, isComparing: boolean) {
|
function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode: VNode, isComparing: boolean) {
|
||||||
let newTextNode: VNode | null = null;
|
let newTextNode: VNode | null = null;
|
||||||
|
|
||||||
// 第一个vNode是Text,则复用
|
// 第一个vNode是Text,则复用
|
||||||
|
@ -628,7 +536,13 @@ function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新节点是对象类型
|
// 新节点是对象类型
|
||||||
function diffObjectNodeHandler(parentNode: VNode, firstChild: VNode | null, newChild: any, isComparing: boolean) {
|
function diffObjectNodeHandler(
|
||||||
|
parentNode: VNode,
|
||||||
|
firstChild: VNode | null,
|
||||||
|
newChild: any,
|
||||||
|
firstChildVNode: VNode,
|
||||||
|
isComparing: boolean
|
||||||
|
) {
|
||||||
let canReuseNode: VNode | null = null;
|
let canReuseNode: VNode | null = null;
|
||||||
|
|
||||||
// 通过key比对是否有可以reuse
|
// 通过key比对是否有可以reuse
|
||||||
|
@ -645,7 +559,7 @@ function diffObjectNodeHandler(parentNode: VNode, firstChild: VNode | null, newC
|
||||||
}
|
}
|
||||||
|
|
||||||
let resultNode: VNode | null = null;
|
let resultNode: VNode | null = null;
|
||||||
let startDelVNode: VNode | null = firstChild;
|
let startDelVNode = firstChildVNode;
|
||||||
if (newChild.vtype === TYPE_COMMON_ELEMENT) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT) {
|
||||||
if (canReuseNode) {
|
if (canReuseNode) {
|
||||||
// 可以复用
|
// 可以复用
|
||||||
|
@ -740,7 +654,7 @@ export function createChildrenByDiff(
|
||||||
|
|
||||||
// 5. newChild是对象类型
|
// 5. newChild是对象类型
|
||||||
if (isObjectType(newChild)) {
|
if (isObjectType(newChild)) {
|
||||||
const newVNodes = diffObjectNodeHandler(parentNode, firstChild, newChild, isComparing);
|
const newVNodes = diffObjectNodeHandler(parentNode, firstChild, newChild, firstChild, isComparing);
|
||||||
if (newVNodes) {
|
if (newVNodes) {
|
||||||
return newVNodes;
|
return newVNodes;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue