十分详细的diff算法原理解析

本文详细介绍了虚拟DOM的diff算法,包括其概念、虚拟DOM的作用、h函数、diff对比规则以及patch过程。diff算法通过对比新旧虚拟DOM找到最小更新路径,避免直接操作真实DOM以提高效率。文章还探讨了key在diff算法中的作用,强调合理使用key能进一步提升页面更新性能。
摘要由CSDN通过智能技术生成

本文我们总结一下有关diff算法的相关内容和实现原理

开门见山,直接先给出大家diff算法的概念

diff算法可以看作是一种对比算法,对比的对象是新旧虚拟Dom。顾名思义,diff算法可以找到新旧虚拟Dom之间的差异,但diff算法中其实并不是只有对比虚拟Dom,还有根据对比后的结果更新真实Dom。

虚拟Dom
上面的概念我们提到了虚拟Dom,相信大家对这个名词并不陌生,下面为大家解释一下虚拟Dom的概念,以及diff算法中为什么要对比虚拟Dom,而不是直接去操作真实Dom。

虚拟Dom,其实很简单,就是一个用来描述真实Dom的对象

它有六个属性,sel表示当前节点标签名,data内是节点的属性,children表示当前节点的其他子标签节点,elm表示当前虚拟节点对应的真实节点(这里暂时没有),key即为当前节点的key,text表示当前节点下的文本,结构类似这样。

let vnode = {
    sel: 'ul', 
    data: {},
    children: [ 
        {
            sel: 'li', data: { class: 'item' }, text: 'son1'
        },
        {
            sel: 'li', data: { class: 'item' }, text: 'son2'
        },    
    ],
    elm: undefined,
    key: undefined,
    text: undefined
}

那么虚拟Dom有什么用呢。我们其实可以把虚拟Dom理解成对应真实Dom的一种状态。当真实Dom发生变化后,虚拟Dom可以为我们提供这个真实Dom变化之前和变化之后的状态,我们通过对比这两个状态,即可得出真实Dom真正需要更新的部分,即可实现最小量更新。在一些比较复杂的Dom变化场景中,通过对比虚拟Dom后更新真实Dom会比直接更新真实Dom的效率高,这也就是虚拟Dom和diff算法真正存在的意义。

h函数
在介绍diff算法原理之前还需要简单让大家了解一下h函数,因为我们要靠它为我们生成虚拟Dom。这个h函数大家应该也比较熟悉,就是render函数里面传入的那个h函数。

h函数可以接受多种类型的参数,但其实它内部只干了一件事,就是执行vnode函数。根据传入h函数的参数来决定执行vnode函数时传入的参数。那么vnode函数又是干什么的呢?vnode函数其实也只干了一件事,就是把传入h函数的参数转化为一个对象,即虚拟Dom。

// vnode.js
export default function (sel, data, children, text, elm) {
    const key = data.key 
    return {sel, data, children, text, elm, key}
}

执行h函数后,内部会通过vnode函数生成虚拟Dom,h函数把这个虚拟在return出去。

diff对比规则
明确了h函数是干什么的,我们可以简单用h函数生成两个不同的虚拟节点,我们将通过一个简易版的diff算法代码介绍diff对比的具体流程。

// 第一个参数是sel 第二个参数是data 第三个参数是children
const myVnode1 = h("h1", {}, [
  h("p", {key: "a"}, "a"),
  h("p", {key: "b"}, "b"),
]);

const myVnode2 = h("h1", {}, [
  h("p", {key: "c"}, "c"),
  h("p", {key: "d"}, "d"),
]);

patch
比较的第一步就是执行patch,它相当于对比的入口。既然是对比两个虚拟Dom,那么就将两个虚拟Dom作为参数传入patch中。patch的主要作用是对比两个虚拟Dom的根节点,并根据对比结果操作真实Dom。

patch函数的核心代码如下,注意注释。

// patch.js

import vnode from "./vnode"
import patchDetails from "./patchVnode"
import createEle from "./createEle"

/**
 * @description 用来对比两个虚拟dom的根节点,并根据对比结果操作真实Dom
 * @param {*} oldVnode 
 * @param {*} newVnode 
 */
export function patch(oldVnode, newVnode) {
  // 1.判断oldVnode是否为虚拟节点,不是的话转化为虚拟节点
  if(!oldVnode.sel) {
    // 转化为虚拟节点
    oldVnode = vnode(oldVnode.tagName.toLowerCase(),

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值