Diff算法
React.js 相对于直接操作原生DOM有很大的性能优势,很大程度上都要归功于virtual DOM的batching和diff。batching把所有的DOM操作搜集起来,一次性提交给真实的DOM。diff算法时间复杂度也从标准的的Diff算法的O(n^3)降到了O(n)。React.js将标准的的Diff算法复杂度O(n^3)直接降低到O(n)基于的假设:
- 两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构
- 对于同一层次的一组子节点,它们可以通过唯一的id进行区分
在比较两个React节点树时,React首先比较根元素,随后的行为取决于根元素类型:
- 只要根节点类型不同,React就会销毁旧节点树,创建新节点树
- 当节点类型相同时,React比较两者的属性,不改变DOM节点,只更新当前节点需要改变的属性
- 如果节点需要更新样式属性,React仅会更新当前节点需要改变的样式属性
React的Diff算法实际上只会对树进行逐层比较。在实现自己的组件时,保持稳定的DOM结构会有助于性能的提升。例如,我们有时可以通过CSS隐藏或显示某些节点,而不是真的移除或添加DOM节点。
key属性在diff算法中的作用
使用浏览器的MutationObserver的功能,对页面上元素的改变进行监听,示例代码如下:
|
|
常规的做法就是将Elong和Qunar组件先删除,然后一次创建和插入Elong、Ly和Qunar组件。通过运行结果可以看出,在React中,Elong组件不变,先将Qunar组件进行删除,然后在创建并插入Ly组件,最后再创建并插入Qunar组件,比常规的做法省去了对Elong组件的删除操作。下面再将主逻辑代码稍作调整,给每个组件添加key属性:
|
|
这次的Diff算法与之前有很大不同,Elong组件不变,Qunar组件不变,只是在Qunar组件之前创建并插入了Ly组件。可见使用key属性可提高渲染性能。