虚拟DOM
什么是DOM
DOM是用一颗逻辑树来表示一个文档,树的每个分支的终点都是一个节点,可以用特定的方式(编写JS、CSS、HTML)来改变这个树的结构,从而改变文档结构、样式或内容。
什么是虚拟DOM
虚拟DOM就是一个JS对象,通过对象的方式来表示DOM结构,通过事务处理机制,将多次DOM修改的结果一次性更新到页面上,从而有效的减少页面渲染次数,减少修改DOM重绘重排的时间,提高渲染性能。
React在内存中维护一个跟真实DOM一样的虚拟DOM树,再改动完组件后,会再生成一个新的虚拟DOM,React会将新的虚拟DOM和原来的虚拟DOM进行对比,找出两个DOM树的不同的地方(diff),然后在真实DOM上更新diff,提高渲染速度。
为什么要使用虚拟DOM
- 提供更好的性能
对比一下修改DOM时真实DOM操作和虚拟DOM的操作:
- 对于真实DOM:生成HTML字符串,重建
所有 DOM元素 - 对于虚拟DOM:生成虚拟DOM节点,采用diff算法,更新出现变化的真实DOM节点
可以看出,虚拟DOM虽然要进行更多的步骤,但它的性能消耗是极低的。
- 跨平台
使用虚拟DOM可以很方便的进行跨平台操作。
diff算法的原理
diff算法探讨的就是虚拟DOM树发生变化后,生成DOM树更新补丁的方式、它通过对比新旧两颗虚拟DOM树的变更差异,将更新补丁作用于真实DOM,以最小的成本完成试图更新。
具体流程如下:
- 真实DOM首先映射为虚拟DOM
- 当虚拟DOM发生变化时,根据变化计算生成
patch ,这个patch 就是一个结构化的数据,包含了增加、更新、删除等操作。 - 根据patch去更新真是DOM,反馈到用户页面上。
这样一个生成补丁,更新差异的过程称为diff算法。
diff算法可以总结为三个策略,分别从树、组件以及元素三个层面进行复杂度优化: 策略一:忽略节点跨层级操作场景,提升对比效率(基于树进行对比) 这一策略需要进行树比对,即对树进行分层比较。树比对的处理手法是非常“暴力”的,即两棵树只对同一层次的节点进行比较,如果发现节点已经不存在了,则该节点及其子节点会被完全删除掉,不会用于进一步的比较,这就提升了比对效率。
策略二:如果组件的class一致,则默认为相似的树结构,否则默认为不同的树结构(基于组件进行对比) 在组件对比中:
- 如果组件是同一类型,则进行树对比
- 如果不是则直接放入补丁中
- 只要父组件类型不同,就会被重新渲染
策略三:同一层级的子节点,可以通过标记 key 的方式进行列表对比。(基于节点进行对比) 元素比对主要发生在同层级中,通过标记节点操作生成补丁。节点操作包含了插入、移动、删除等。其中节点重新排序同时涉及插入、移动、删除三个操作,所以效率消耗最大,此时策略三起到了至关重要的作用。通过标记 key 的方式,React 可以直接移动 DOM 节点,降低内耗。
React中的key是什么
key是React用于追踪哪些列表中元素被修改、被添加、被移除的辅助标识。在开发中,我们要保证每个元素的key在其同级的元素具有唯一性。
diff算法中会借助key来判断该元素是新创建的还是被移动而来的元素,从而减少不必要的渲染。
- key具有唯一性
- 尽量不要用数组中的index作为key
- 不要再render的时候使用随机数或其它操作给元素加上不稳定的key,因为这样造成的性能开销比不加key更多
|