一、虚拟DOM
1. 内部执行流程
- 用 JS对象结构表示 DOM 树的结构,然后用这个树构建一个真正的 DOM 树,插到文档中;当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异;把记录的差异应用到真正的DOM树上,视图就更新了。
- 将真实的DOM树,映射成一个虚拟的DOM对象,操作时,操作虚拟DOM对象,不直接操作DOM对象,合并多个修改操作,最后一起修改DOM,批量更新,减少更新的次数。虚拟DOM其实就是用一个对象来描述DOM,通过对比前后两个对象的差异,最终只把变化的部分重新渲染,提高渲染的效率。
- 当DOM发生更改时需要遍历DOM对象的属性, 而原生DOM可遍历属性多达200多个, 而且大部分属性与渲染无关, 导致更新页面代价太大。
2. 原理剖析
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,硬盘读取速度比较慢,我们会就在它们之间加缓存条;反之, 既然 DOM 运行速度慢,那么我们就在JS 和 DOM 之间加个缓存。JS只操作Virtual DOM,最后的时候再把变更的结果写入DOM。
3. 优势
虚拟DOM避免了直接操作DOM带来的频繁渲染更新问题,将多次会触发DOM重新渲染的操作合并为一次进行统一渲染。
通过批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分,可以保证非常高效的渲染,优化性能。
4. 劣势
在DOM操作不是很频繁的情况下,使用虚拟DOM反而适得其反;首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
二、diff算法
- 对比计算后,只更新数据变化的DOM对象,最小化界面重绘。
- 当我们使用React在render() 函数创建了一棵React元素树,在下一个state或者props更新的时候,render() 函数将会创建一棵新的React元素树,React将对比这两棵树的不同之处,计算出如何高效的更新UI(只更新变化的地方),此处所采用的算法就是diff算法。
- 如果两棵树的根元素类型不同,React会销毁旧树,创建新树。
- 对于类型相同的React DOM 元素,React会对比两者的属性是否相同,只更新不同的属性; 当处理完这个DOM节点,React就会递归处理子节点。
- 遍历插入元素,如果没有key,React将改变每一个子节点,即删除重新创建;为了解决这个问题,React提供了一个 key 属性。当子节点带有key属性,React会通过key来匹配原始树和后来的树。
- 例如:通过绑定key,React就知道带有key ‘1024’ 的元素是新的,对于 ‘1025’ 和 ‘1026’ 仅仅移动位置即可。
- key属性只会在React内部使用,不会传递给组件。
- key只需要保持与他的兄弟节点唯一即可,不需要全局唯一。