vue-diff算法之原理——上

135 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

核心概念

vue diff 算法是针对于大多数合理的场景的,首先会从头开始比较,如果可以复用就复用,然后从后往前比较,可以复用就复用。最后剩下一些不是特别有规律的结构,然后再通过算法,尽可能的复用dom,不能复用的直接创建新的节点。

第一步创建一个工具函数,判断两个dom是否类型相同,key相同,如果类型和key都相同,说明该dom是可以直接复用的,否则就不会复用 此处为了简单,直接比较一个key,就不比较type了

function isSameVNodeType(n1, n2) {
  return n1.key === n2.key;
}

紧接着创建diff方法,diffArray方法接收两个dom Array,然后第三个参数是一些真实dom操作的帮助方法

function mountElement(key) {
  console.log(key, 'mountElement')
}

function patch(key) {
  console.log(key, 'patch')
}

function unmount(key) {
  console.log(key, 'unmount')
}

function move(key) {
  console.log(key, 'move')
}
let action = {
  mountElement,
  patch,
  unmount,
  move
}
function diffArray(c1, c2, {
  mountElement,
  patch,
  unmount,
  move
}) {
    
}

diffArray方法,使用方式如下,虚拟dom本身就是js对象,本案例中仅仅是包含了key,其他属性这里就不做具体的模拟了。大概的目的,就是将list1(老节点)中的可以复用的尽量的复用,然后需要移动的尽量的做到最少的移动。

let list1 = [{
    key: "a",
  },
  {
    key: "b",
  },
  {
    key: "c",
  },
  {
    key: "d",
  },
  {
    key: "e",
  },
  {
    key: "f",
  },
  {
    key: "g",
  },
];
let list2 = [{
    key: "a",
  },
  {
    key: "b",
  },
  {
    key: "e",
  },
  {
    key: "c",
  },
  {
    key: "d",
  },
  {
    key: "h",
  },
  {
    key: "f",
  },
  {
    key: "g",
  },
];
diffArray(list1, list2, action)

diffArray里首先做的是,记录一下新老节点的结束索引endIndex,和开始位置i=0;

function diffArray(c1, c2, {
  mountElement,
  patch,
  unmount,
  move
}) {
  let i = 0;
  let e1 = c1.length - 1;
  let e2 = c2.length - 1;
    
}

然后假设这两个dom列表的开头都是可以复用的,老的节点第一个和新的节点第一个比较,如果可以复用,索引➕1,对比第二个,直到老的节点不可复用后结束这个操作,有时候可能第一个就不可以复用,但是无所谓。这个尝试无论对时间或者空间的损耗都极低。 patch方法就是常说的打补丁。

function diffArray(c1, c2, {
  mountElement,
  patch,
  unmount,
  move
}) {

 ... 
  while (i <= e1 && i <= e2) {
    const n1 = c1[i];
    const n2 = c2[i];
    if (isSameVNodeType(n1, n2)) {
      patch(n1.key);
    } else {
      break;
    }
    i++;
  }
 }

代码写到这里,就可以处理没有新增和删除的情况了,所有节点都可以复用,所有节点只是打patch就行了 基于这代码前面两个节点a,b就是可以复用的

image.png 不行了,脑子不够用了,明天接着往下写中吧