首页 > 编程语言 >【Vue面试题】谈谈你对Vue的diff算法的理解

【Vue面试题】谈谈你对Vue的diff算法的理解

时间:2022-08-29 23:55:09浏览次数:82  
标签:对比 面试题 Vue DOM vnode oldVnode diff 节点

1 diff算法到底是什么?

diff算法是一种通过同层的节点进行比较的高效算法,它可以不用频繁操作DOM,而是选用虚拟DOM节点操作,说人话就是专门用来处理虚拟DOM节点的。

2 操作流程?

为了更好理解Vuediff算法,请先看一位B站大佬精心制作的

动画演示

通过上面视频可以很好理解diff算法的比较流程,清楚在循环从左右两边向中间比较的更新、插入、删除、查询操作。

它的操作本质就是:
分别遍历新旧虚拟DOM节点的数组,接着通过循环左右双指针比较判断。

新的头 newStartIndex 和老的头 oldStartIndex 对比

新的尾 newEndIndex 和老的尾 oldEndIndex 对比

新的头 newStartIndex 和老的尾 oldEndIndex 对比

新的尾 newEndIndex 和老的头 oldStartIndex 对比

3 解析github源码

我看到掘金的一篇讲的很不错,可以看看,深入浅出虚拟 DOM 和 Diff 算法,及 Vue2 与 Vue3 中的区别,我就只负责总结一下学习笔记吧。

3.1 patch函数:对比新旧虚拟DOM

3.1.1 什么时候触发?

在页面首次渲染的时候会调用一次 patch 并创建新的 vnode,不会进行更深层次的比较。

在组件中数据发生变化时:

  1. 先触发 setter 然后通过 Notify 通知 Watcher
  2. 对应的 Watcher 会通知更新并执行更新函数,它会执行 render 函数获取新的虚拟 DOM
  3. 执行 patch 对比上次渲染结果的老的虚拟 DOM,并计算出最小的变化,然后再去根据这个最小的变化去更新真实的 DOM,也就是视图View

3.1.2 patch的更新流程流程(源码第700行)

3.2 patchVnode函数:对比节点文本变化或子节点变化

  • 如果 oldVnodevnode 的引用地址是一样的,就表示节点没有变化,直接返回。
  • 通过 oldVnodeisAsyncPlaceholder 判断注释、v-if 和异步函数的情况,选择跳过异步组件的检查,直接返回。
  • 如果 oldVnodevnode 都是静态节点,有相同的 key
    • vnode 是克隆节点或者 v-once 指令控制的节点时
      • oldVnode.elmoldVnode.child 都复制到 vnode 上,然后返回。
  • 如果 vnode 不是文本节点也不是注释的情况下:
    • 如果 vnode 文本为 undefined,就删掉 vnode.elm 文本
    • 如果 vnodeoldVnode 都有子节点,而且子节点不一样的话,就调用 updateChildren 更新子节点
    • 如果只有 vnode 有子节点,就调用 addVnodes 创建子节点
    • 如果只有 oldVnode 有子节点,就调用 removeVnodes 删除该子节点
  • 如果 vnode 是文本节点但是和 oldVnode 文本内容不一样,就更新文本

3.3 updateChildren:对比子节点的函数

当每轮循环对比时都不能满足找到对应的key值与标签值一致的情况时,那么要不断拿 新的开始节点 的 key 去 老的开始节点的子节点 children 找。

  • 如果没找到,就创建一个新的节点
  • 如果找到了,再对比标签是不是同一个节点
    • 如果是同一个节点,就调用 patchVnode 进行后续对比,然后把这个节点插入到 老的开始节点 前面,并且移动新的开始下标,继续下一轮循环对比
    • 如果不是相同节点,就创建一个新的节点
  • 如果老的 vnode 先遍历完,就添加新的 vnode 没有遍历的节点
  • 如果新的 vnode 先遍历完,就删除老的 vnode 没有遍历的节点

标签:对比,面试题,Vue,DOM,vnode,oldVnode,diff,节点
From: https://www.cnblogs.com/PaturNax/p/16637349.html

相关文章

  • vue学习之------vue-router【路由生命周期(也叫“导航守卫”)】
    1、全局导航守卫2、路由规则自己的守卫3、组件内部的导航守卫 ......
  • vue3 基础-事件绑定 & 修饰符
    无非就是js的一些事件,按键,鼠标等的一些绑定在vue的实现而已,很好理解.先来看一个基础例子.事件初体验<!DOCTYPEhtml><htmllang="en"><head><title>事......
  • Vue面试题之如何解决vue第一次加载的时候 页面上使用的数据会闪烁?
    引起数据闪烁的原因:界面加载的时候会把节点直接挂载到文档树中,导致{{msg+"666"}}这个字符串会显示一下,vue对象生成data数据时候回去刷新界面把{{msg+"666"}}字符串替换成......
  • Vue的基础指令
    1.普通插值表达式插入数据<body> <divid="app"> <div>{{text1}}</div> <div>{{text2}}</div> </div></body><script> newVue({ el:"#app", data:{ tex......
  • 什么是vue⽣命周期?
    什么是vue⽣命周期?vue⽣命周期都有哪些钩⼦函数?这些钩⼦函数如何触发? 项⽬开发过程中,在⽣命周期⾥⾯都分别做过什么功能? ⻚⾯第⼀次加载时⽗⼦组件⽣命周期执⾏的顺......
  • 给vue单页面绑定快捷键
    created(){//添加快捷键document.addEventListener('keyup',this.handleKeyUp)},destroyed(){//删除快捷键document.removeEventListene......
  • 引入VUE的方式(8种)
    第一类:1、本地引入把vue的js文件下载下来引入   2、CDN引入把vue.js网址引入   3、把vue.js文件放在项目文件夹src中引入项目然后webpack打包 4、......
  • Vite 按需引入 Ant Design Vue 3.0
    Vite按需引入AntDesignVue3.0第一步下载:npmiunplugin-vue-components-D需要注意的是:Vite你可以用unplugin-vue-components来进行按需加载。但是此插件无法处......
  • 50道Redis高频面试题
    一、Redis到底是单线程还是多线程Redis6.0版本之前的单线程指的是其网络I/O和键值对读写是由一个线程完成。也就是只有网络请求模块和数据操作模块是单线程的,而其他的持......
  • CentOS 安装Nginx并部署vue项目
    安装yuminstallnginx配置nginx设置开机启动systemctlenablenginx启动服务systemctlstartnginx停止服务systemctlstopnginx重启服务syst......