沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 课程导读-必看
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
    • 图解快速diff
    • 最长递增子序列
    • 模板编译器
    • 模板编译提升
    • 组件name作用
    • Vue项目性能优化
    • 路由传参方式
    • vue3笔面试题汇总
    luzhichang
    2024-09-27
    目录

    图解双端diff

    # 图解双端diff

    面试题:说一下 Vue3 中的 diff 相较于 Vue2 有什么变化?

    • Vue2: 双端diff
    • Vue3: 快速diff

    1. diff的概念

    diff 算法是用于比较两棵虚拟 DOM 树的算法,目的是找到它们之间的差异,并根据这些差异高效地更新真实 DOM,从而保证页面在数据变化时只进行最小程度的 DOM 操作。

    思考🤔:为什么需要进行diff,不是已经有响应式了么?

    答案:响应式虽然能够侦测到响应式数据的变化,但是只能定位到组件,代表着某一个组件要重新渲染。组件的重新渲染就是重新执行对应的渲染函数,此时就会生成新的虚拟 DOM 树。但是此时我们并不知道新树和旧树具体哪一个节点有区别,这个时候就需要diff算法来找到两棵树的区别。

    20210301193804

    2. diff算法的特点

    1. 分层对比:它会逐层对比每个节点和它的子节点,避免全树对比,从而提高效率。
    2. 相同层级节点对比:在进行 diff 对比的时候,Vue会假设对比的节点是同层级的,也就是说,不会做跨层的比较。
    20210301203350

    3. diff算法详细流程

    1. 从根节点开始比较,看是否相同。所谓相同,是指两个虚拟节点的标签类型、key 值均相同,但 input 元素还要看 type 属性

      1. 相同
        • 相同就说明能够复用,此时就会将旧虚拟DOM节点对应的真实DOM赋值给新虚拟DOM节点
        • 对比新节点和旧节点的属性,如果属性有变化更新到真实DOM. 这说明了即便是对 DOM 进行复用,也不是完全不处理,还是会有一些针对属性变化的处理
        • 进入【对比子节点】
      2. 不相同
        • 如果不同,该节点以及往下的子节点没有意义了,全部卸载
          • 直接根据新虚拟DOM节点递归创建真实DOM,同时挂载到新虚拟DOM节点
          • 销毁旧虚拟DOM对应的真实DOM,背后调用的是 vnode.elm.remove( ) 方法
    2. 对比子节点:

      1. 仍然是同层做对比
      2. 深度优先
      3. 同层比较时采用的是双端对比
      image-20240906101143754

    4. 双端对比

    之所以被称之为双端,是因为有两个指针,一个指向头节点,另一个指向尾节点,如下所示:

    image-20240913225147579

    无论是旧的虚拟 DOM 列表,还是新的虚拟 DOM 列表,都是一头一尾两个指针。

    接下来进入比较环节,整体的流程为:

    1. 步骤一:新头和旧头比较

      • 相同:

        • 复用 DOM 节点

          image-20240914101542039
        • 新旧头索引自增

          image-20240914101629244
        • 重新开始步骤一

      • 不相同:进入步骤二

    2. 步骤二:新尾和旧尾比较

      • 相同:

        • 复用 DOM 节点

          image-20240914101834010
        • 新旧尾索引自减

          image-20240914101913347
        • 重新开始步骤一

      • 不相同,进入步骤三

    3. 步骤三:旧头和新尾比较

      • 相同:

        • 说明可以复用,并且说明节点从头部移动到了尾部,涉及到移动操作,需要将旧头对应的 DOM 节点移动到旧尾对应的 DOM 节点之后

          image-20240914101231300
        • 旧头索引自增,新尾索引自减

          image-20240914101400686
        • 重新开始步骤一

      • 不相同,进入步骤四

    4. 步骤四:新头和旧尾比较

      • 相同:

        • 说明可以复用,并且说明节点从尾部移动到了头部,仍然涉及到移动操作,需要将旧尾对应的 DOM 元素移动到旧头对应的 DOM 节点之前

          image-20240914105559210
        • 新头索引自增,旧尾索引自减

          image-20240914105649208
        • 重新开始步骤一

      • 不相同:进入步骤五

    5. 暴力比较:上面 4 个步骤都没找到相同的,则采取暴力比较。在旧节点列表中寻找是否有和新节点相同的节点,

      • 找到

        • 说明是一个需要移动的节点,将其对应的 DOM 节点移动到旧头对应的 DOM 节点之前

          image-20240914110012627
        • 新头索引自增

          image-20240914110048026
        • 回到步骤一

      • 没找到

        • 说明是一个新的节点,创建新的 DOM 节点,插入到旧头对应的 DOM 节点之前

          image-20240914110332605
        • 新头索引自增

          image-20240914110401233
        • 回到步骤一

    新旧节点列表任意一个遍历结束,也就是 oldStart > OldEnd 或者 newStart > newEnd 的时候,diff 比较结束。

    • 旧节点列表有剩余(newStart > newEnd):对应的旧 DOM 节点全部删除掉
    • 新节点列表有剩余(oldStart > OldEnd):将新节点列表中剩余的节点创建对应的 DOM,放置于新头节点对应的 DOM 节点后面

    综合示例

    当前旧 Vnode 和新 VNode 如下图所示:

    image-20240914111038061
    1. 头头对比,能够复用,新旧头指针右移

      image-20240914111750328
    2. 头头不同,尾尾相同,能够复用,尾尾指针左移

      image-20240914111936261
    3. 头头不同,尾尾不同,旧头新尾相同,旧头对应的真实DOM移动到旧尾对应的真实DOM之后,旧头索引自增,新尾索引自减

      image-20240914112233100
    4. 头头不同,尾尾不同,旧头新尾不同,新头旧尾相同,旧尾对应的真实DOM移动到旧头对应的真实DOM之前,新头索引自增,旧尾索引自减

      image-20240914112710405
    5. 头头不同,尾尾不同,旧头新尾不同,新头旧尾不同,进入暴力对比,找到对应节点,将对应的真实DOM移动到旧头对应的真实DOM之间,新头索引自增

      image-20240914113000896
    6. 头头不同,尾尾不同,旧头新尾不同,新头旧尾相同,将旧尾对应的真实DOM移动到旧头对应的真实DOM之前,新头索引自增,旧尾索引自减

      image-20240914113247844
    7. 头头不同,尾尾不同,旧头新尾不同,新头旧尾不同,暴力对比发现也没找到,说明是一个全新的节点,创建新的DOM节点,插入到旧头对应的DOM节点之前,新头索引自增

      image-20240914113444878
    8. newEnd > newStart,diff 比对结束,旧 VNode 列表还有剩余,直接删除即可。

      image-20240914113721337

    -EOF-

    watch面试题
    图解快速diff

    ← watch面试题 图解快速diff→

    Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式