Skip to content

Commit

Permalink
更新 element 的 children - 双端对比diff 算法 (2)
Browse files Browse the repository at this point in the history
  • Loading branch information
jindy committed Jun 18, 2022
1 parent a0b701b commit 39ed1f4
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 26 deletions.
52 changes: 26 additions & 26 deletions example/PatchChildren/ArrayToArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ import { h,ref } from '../../lib/guide-mini-vue.esm.js'
// (b c)
// i = 0, e1 = 0, e2 = -1

const prevChildren = [
h("p", { key: "A" }, "A"),
h("p", { key: "B" }, "B"),
h("p", { key: "C" }, "C"),
];
const nextChildren = [h("p", { key: "B" }, "B"), h("p", { key: "C" }, "C")];
// const prevChildren = [
// h("p", { key: "A" }, "A"),
// h("p", { key: "B" }, "B"),
// h("p", { key: "C" }, "C"),
// ];
// const nextChildren = [h("p", { key: "B" }, "B"), h("p", { key: "C" }, "C")];

// 5. 对比中间的部分
// 删除老的 (在老的里面存在,新的里面不存在)
Expand Down Expand Up @@ -165,27 +165,27 @@ const nextChildren = [h("p", { key: "B" }, "B"), h("p", { key: "C" }, "C")];
// a,b,(d,c,y,e),f,g
// 最长子序列: [1,3]

// const prevChildren = [
// h("p", { key: "A" }, "A"),
// h("p", { key: "B" }, "B"),
// h("p", { key: "C" }, "C"),
// h("p", { key: "D" }, "D"),
// h("p", { key: "E" }, "E"),
// h("p", { key: "Z" }, "Z"),
// h("p", { key: "F" }, "F"),
// h("p", { key: "G" }, "G"),
// ];
const prevChildren = [
h("p", { key: "A" }, "A"),
h("p", { key: "B" }, "B"),
h("p", { key: "C" }, "C"),
h("p", { key: "D" }, "D"),
h("p", { key: "E" }, "E"),
h("p", { key: "Z" }, "Z"),
h("p", { key: "F" }, "F"),
h("p", { key: "G" }, "G"),
];

// const nextChildren = [
// h("p", { key: "A" }, "A"),
// h("p", { key: "B" }, "B"),
// h("p", { key: "D" }, "D"),
// h("p", { key: "C" }, "C"),
// h("p", { key: "Y" }, "Y"),
// h("p", { key: "E" }, "E"),
// h("p", { key: "F" }, "F"),
// h("p", { key: "G" }, "G"),
// ];
const nextChildren = [
h("p", { key: "A" }, "A"),
h("p", { key: "B" }, "B"),
h("p", { key: "D" }, "D"),
h("p", { key: "C" }, "C"),
h("p", { key: "Y" }, "Y"),
h("p", { key: "E" }, "E"),
h("p", { key: "F" }, "F"),
h("p", { key: "G" }, "G"),
];

// 3. 创建新的节点
// a,b,(c,e),f,g
Expand Down
113 changes: 113 additions & 0 deletions lib/guide-mini-vue.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,78 @@ function createRenderer(options) {
i++;
}
}
else {
// 5. 对比中间的部分
let s1 = i;
let s2 = i;
const toBePatched = e2 - s2 + 1;
let patched = 0;
const keyToNewIndexMap = new Map();
const newIndexToOldIndexMap = new Array(toBePatched);
let moved = false;
let maxNewIndexSoFar = 0;
for (let index = 0; index < toBePatched; index++)
newIndexToOldIndexMap[index] = 0;
for (let index = s2; index <= e2; index++) {
const nextChild = child2[index];
keyToNewIndexMap.set(nextChild.key, index);
}
for (let index = s1; index <= e1; index++) {
const prevChild = child1[index];
if (patched >= toBePatched) {
hostRemove(prevChild.el);
continue;
}
// null undefined
let newIndex;
if (prevChild.key !== null) {
newIndex = keyToNewIndexMap.get(prevChild.key);
}
else {
for (let j = s2; j <= e2; j++) {
if (isSomeVNodeType(prevChild, child2[j])) {
newIndex = j;
break;
}
}
}
if (newIndex === undefined) {
hostRemove(prevChild.el);
}
else {
if (newIndex >= maxNewIndexSoFar) {
maxNewIndexSoFar = newIndex;
}
else {
moved = true;
}
newIndexToOldIndexMap[newIndex - s2] = i + 1;
patch(prevChild, child2[newIndex], container, parentComponent, null);
patched++;
}
}
const increasingNewIndexSequence = moved
? getSequence(newIndexToOldIndexMap)
: [];
let j = increasingNewIndexSequence.length - 1;
for (let index = toBePatched - 1; index >= 0; index--) {
const nextIndex = index + s2;
const nextChild = child2[nextIndex];
const anchor = nextIndex + 1 < l2 ? child2[nextIndex + 1].el : null;
if (newIndexToOldIndexMap[index] === 0) {
patch(null, nextChild, container, parentComponent, anchor);
}
else if (moved) {
if (j < 0 || index !== newIndexToOldIndexMap[j]) {
// 移动
hostInsert(nextChild.el, container, anchor);
}
else {
j--;
}
}
}
}
}
function unmountChildren(children) {
for (let index = 0; index < children.length; index++) {
Expand All @@ -652,6 +724,47 @@ function createRenderer(options) {
createApp: createAppAPI(render),
};
}
function getSequence(arr) {
const p = arr.slice();
const result = [0];
let i, j, u, v, c;
const len = arr.length;
for (i = 0; i < len; i++) {
const arrI = arr[i];
if (arrI !== 0) {
j = result[result.length - 1];
if (arr[j] < arrI) {
p[i] = j;
result.push(i);
continue;
}
u = 0;
v = result.length - 1;
while (u < v) {
c = (u + v) >> 1;
if (arr[result[c]] < arrI) {
u = c + 1;
}
else {
v = c;
}
}
if (arrI < arr[result[u]]) {
if (u > 0) {
p[i] = result[u - 1];
}
result[u] = i;
}
}
}
u = result.length;
v = result[u - 1];
while (u-- > 0) {
result[u] = v;
v = p[v];
}
return result;
}

// 创建
function createElement(type) {
Expand Down
113 changes: 113 additions & 0 deletions lib/guide-mini-vue.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,78 @@ function createRenderer(options) {
i++;
}
}
else {
// 5. 对比中间的部分
let s1 = i;
let s2 = i;
const toBePatched = e2 - s2 + 1;
let patched = 0;
const keyToNewIndexMap = new Map();
const newIndexToOldIndexMap = new Array(toBePatched);
let moved = false;
let maxNewIndexSoFar = 0;
for (let index = 0; index < toBePatched; index++)
newIndexToOldIndexMap[index] = 0;
for (let index = s2; index <= e2; index++) {
const nextChild = child2[index];
keyToNewIndexMap.set(nextChild.key, index);
}
for (let index = s1; index <= e1; index++) {
const prevChild = child1[index];
if (patched >= toBePatched) {
hostRemove(prevChild.el);
continue;
}
// null undefined
let newIndex;
if (prevChild.key !== null) {
newIndex = keyToNewIndexMap.get(prevChild.key);
}
else {
for (let j = s2; j <= e2; j++) {
if (isSomeVNodeType(prevChild, child2[j])) {
newIndex = j;
break;
}
}
}
if (newIndex === undefined) {
hostRemove(prevChild.el);
}
else {
if (newIndex >= maxNewIndexSoFar) {
maxNewIndexSoFar = newIndex;
}
else {
moved = true;
}
newIndexToOldIndexMap[newIndex - s2] = i + 1;
patch(prevChild, child2[newIndex], container, parentComponent, null);
patched++;
}
}
const increasingNewIndexSequence = moved
? getSequence(newIndexToOldIndexMap)
: [];
let j = increasingNewIndexSequence.length - 1;
for (let index = toBePatched - 1; index >= 0; index--) {
const nextIndex = index + s2;
const nextChild = child2[nextIndex];
const anchor = nextIndex + 1 < l2 ? child2[nextIndex + 1].el : null;
if (newIndexToOldIndexMap[index] === 0) {
patch(null, nextChild, container, parentComponent, anchor);
}
else if (moved) {
if (j < 0 || index !== newIndexToOldIndexMap[j]) {
// 移动
hostInsert(nextChild.el, container, anchor);
}
else {
j--;
}
}
}
}
}
function unmountChildren(children) {
for (let index = 0; index < children.length; index++) {
Expand All @@ -648,6 +720,47 @@ function createRenderer(options) {
createApp: createAppAPI(render),
};
}
function getSequence(arr) {
const p = arr.slice();
const result = [0];
let i, j, u, v, c;
const len = arr.length;
for (i = 0; i < len; i++) {
const arrI = arr[i];
if (arrI !== 0) {
j = result[result.length - 1];
if (arr[j] < arrI) {
p[i] = j;
result.push(i);
continue;
}
u = 0;
v = result.length - 1;
while (u < v) {
c = (u + v) >> 1;
if (arr[result[c]] < arrI) {
u = c + 1;
}
else {
v = c;
}
}
if (arrI < arr[result[u]]) {
if (u > 0) {
p[i] = result[u - 1];
}
result[u] = i;
}
}
}
u = result.length;
v = result[u - 1];
while (u-- > 0) {
result[u] = v;
v = p[v];
}
return result;
}

// 创建
function createElement(type) {
Expand Down
Loading

0 comments on commit 39ed1f4

Please sign in to comment.