React之虚拟DOM的实现原理.docx
第
React之虚拟DOM的实现原理
目录React虚拟DOM机制Reactdiff算法1.传统diff算法2.reactdiff算法总结最后
React虚拟DOM机制
虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象状态变更时,记录新树和旧树的差异最后把差异更新到真正的dom中
React引入了虚拟DOM(VirtualDOM)的机制:在浏览器端用Javascript实现了一套DOMAPI。
基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。
而且React能够批量处理虚拟DOM的刷新,在一个事件循环(EventLoop)内的两次数据变化会被合并,例如你连续的先将节点内容从A变成B,然后又从B变成A,React会认为UI不发生任何变化。
尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,而对实际DOM进行操作的仅仅是Diff部分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。
总之一句话:根据React的设计,所有的DOM变动,都先在虚拟DOM上发生,然后再将实际发生变动的部分,反映在真实DOM上
Reactdiff算法
diff算法作为VirtualDOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最不可思议的部分。
1.传统diff算法
计算一棵树形结构转换为另一棵树形结构需要最少步骤,如果使用传统的diff算法通过循环递归遍历节点进行对比,其复杂度要达到O(n^3),其中n是节点总数,效率十分低下,假设我们要展示1000个节点,那么我们就要依次执行上十亿次的比较。
下面附上一则简单的传统diff算法:
letresult=[];
//比较叶子节点
constdiffLeafs=function(beforeLeaf,afterLeaf){
//获取较大节点树的长度
letcount=Math.max(beforeLeaf.children.length,afterLeaf.children.length);
//循环遍历
for(leti=0;icount;i++){
constbeforeTag=beforeLeaf.children[i];
constafterTag=afterLeaf.children[i];
//添加afterTag节点
if(beforeTag===undefined){
result.push({type:add,element:afterTag});
//删除beforeTag节点
}elseif(afterTag===undefined){
result.push({type:remove,element:beforeTag});
//节点名改变时,删除beforeTag节点,添加afterTag节点
}elseif(beforeTag.tagName!==afterTag.tagName){
result.push({type:remove,element:beforeTag});
result.push({type:add,element:afterTag});
//节点不变而内容改变时,改变节点
}elseif(beforeTag.innerHTML!==afterTag.innerHTML){
if(beforeTag.children.length===0){
result.push({
type:changed,
beforeElement:beforeTag,
afterElement:afterTag,
html:afterTag.innerHTML
}else{
//递归比较
diffLeafs(beforeTag,afterTag);
r