一、DOM树
1、定义:
用于表示基于HTML或者XML的标记语言文档并能与之交互的API。它是加载在浏览器中的文档模型,可以将文档表示为节点树,或称 DOM 树,其中每个节点代表文档的一部分。
2、作用:
允许在浏览器中运行的代码访问文档中的每个节点并与之交互。可以创建、移动和更改节点,还可以将事件监听器添加到节点,并在特定事件发生时触发。
3、性能瓶颈
直接操作DOM可能引发浏览器的重排和重绘。如果频繁或者复杂地操作DOM,会大量消耗性能,导致页面卡顿。
二、虚拟DOM
1、实质
一个描述真实DOM结构的js对象
const vnode = {
type: 'div',
props: {
id: 'hello'
},
children: [
/* 更多 vnode */
]
}
2、作用
提供一种高效的方式来计算出dom的最小变更,并批量、高效地应用到真实DOM上。
优点:
- “声明式UI” 的技术基础。开发者直接告诉程序“在状态A下,视图应该是B”,而不是用命令式代码一步步指挥(“如果A变了,就找到C元素,然后修改它的D属性”)。大大简化了UI开发的复杂度。
- 抽象与跨平台:虚拟DOM最大的价值之一是提供了抽象层。开发者通过描述“应该是什么样子”来编程,而不必亲自操作具体的DOM API。这使得Vue等框架不仅可以渲染到浏览器DOM,还能相对容易地渲染到原生移动应用(如Weex/NativeScript)、Canvas、甚至是终端命令行界面。渲染器(Renderer)接收虚拟DOM并转换为特定平台的UI。
3、过程
- 编译:Vue模版被编译为渲染函数(用来返回虚拟DOM树)的函数,
- 挂载(mount):初次渲染时,根据虚拟DOM树创建整个真实DOM树
- 更新(patch/diffing):当状态发生变化,会生成新的虚拟DOM树。渲染器通过Diff算法将新旧两棵虚拟DOM树进行比对,精确找出差异所在。(优点:算法会高效地遍历两棵树,只在同一层级进行比较,避免了跨层级的开销,只针对发生变化的部分生成对应的DOM操作指令)
- 批量提交:将计算出的所有DOM操作批量作用到真实DOM上,减少了直接操作DOM的次数,避免不必要的重排重绘。
4、不足
- 需要额外的内存来创建和存储虚拟DOM,需要CPU时间来进行Diff计算。是用JS的计算开销来换取减少DOM操作开销的方法。(对大部分应用来说是值得的,因为JS计算比DOM操作更快)
- 并非是绝对最快的:手工编写优化的命令式DOM操作可能比虚拟DOM的更新更快
三、Vue3 生命周期
组合式 API 中的 setup() 钩子会在所有选项式 API 钩子之前调用
nextTick()
在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。
nextTick()可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。
优点:等待Vue完成所有组件的DOM更新,保证操作的是最终的DOM。