Diff exists in both Vue and React. The difference is that Vue controls diff in components, while React is optimized by Fiber. So let’s take diff in its simplest form.

The diff function compares the old VNode with the new one, and then performs patch to update the DOM. Key is important in this process, and I’ve simplified VNode for your understanding. Use {key: XXX} to represent a VNode.

Diff’s goal: Creating a DOM consumes performance, so try to move the DOM that exists in oldVNode. Create the ones that do not exist and delete the ones that are redundant.

Approach!

1. Create newVNode and oldVNode

const oldVNode = [
    { key: 1 }, { key: 2 }, { key: 3 }, { key: 4 }, { key: 5 },
    { key: 6 }, { key: 7 }, { key: 8 }, { key: 9 }, { key: 10}]const newVNode = [
    { key: 1 }, { key: 10 }, { key: 9 }, { key: 5 },
    { key: 22 }, { key: 8 }, { key: 7 }, { key: 2 },
    { key: 17}]Copy the code

2. Create a map and store all keys in the oldVNode

const map = new Map(a);for (let i of oldVNode) {
    map.set(i.key, i)
}
Copy the code

3. Use the ‘two-pointer’ method for comparison

Because it is array emulation, splice is used to simulate DOM movement, creation, and deletion.

let newIndex = 0;
let oldIndex = 0;
// 'double pointer' cannot exceed the limit
while (newIndex < newVNode.length && oldIndex < oldVNode.length) {
    // newVNode[newIndex] does not exist in oldVNode
    if(! map.has(newVNode[newIndex])) {// Create newVNode[newIndex] in oldVNode
        oldVNode.splice(newIndex, 0, newVNode[newIndex])
        // Update the pointer
        newIndex++;
        oldIndex++;
    } else { // When newVNode[newIndex] exists in oldVNode
        // newVNode[newIndex] and oldVNode[oldIndex] are not equal
        if(newVNode[newIndex] ! == oldVNode[oldIndex]) {/ / update the oldIndex
            oldIndex++;
        } else { // newVNode[newIndex] and oldVNode[oldIndex] are not equal
            // Use the following code to simulate DOM movement
            const dom = oldVNode.splice(oldVNode, 1);
            oldVNode.splice(newIndex, 0. dom);// Update the pointernewIndex++; oldIndex = newIndex; }}}Copy the code

4. Because of the “two-pointer” bound, we have to deal with the rest of the DOM

// If the oldVNode is free, delete all oldvNodes
if (oldIndex < oldVNode.length) {
    oldVNode.splice(oldIndex)
}
// If newIndex is available, create all of them
if(newIndex < newVNode.length) { oldVNode.push(... newVNode.slice(newIndex)) }Copy the code

All the code

const oldVNode = [
    { key: 1 },
    { key: 2 },
    { key: 3 },
    { key: 4 },
    { key: 5 },
    { key: 6 },
    { key: 7 },
    { key: 8 },
    { key: 9 },
    { key: 10}]const newVNode = [
    { key: 1 },
    { key: 10 },
    { key: 9 },
    { key: 5 },
    { key: 22 },
    { key: 8 },
    { key: 7 },
    { key: 2 },
    { key: 17},]const map = new Map(a);for (let i of oldVNode) {
    map.set(i.key, i)
}
let newIndex = 0;
let oldIndex = 0;
while (newIndex < newVNode.length && oldIndex < oldVNode.length) {
    if(! map.has(newVNode[newIndex])) { oldVNode.splice(newIndex,0, newVNode[newIndex])
        newIndex++;
        oldIndex++;
    } else {
        if(newVNode[newIndex] ! == oldVNode[oldIndex]) { oldIndex++; }else {
            const dom = oldVNode.splice(oldVNode, 1);
            oldVNode.splice(newIndex, 0. dom); newIndex++; oldIndex = newIndex; }}}if (oldIndex < oldVNode.length) {
    oldVNode.splice(oldIndex)
}
if(newIndex < newVNode.length) { oldVNode.push(... newVNode.slice(newIndex)) }console.log(oldVNode)
console.log(newVNode)

Copy the code