React Diff 算法
React介绍React是Facebook开发的一款JS库,用于构建用户界面的类库。 它采用声明式范例,可以传递声明代码,最大限度地减少与DOM的交互。 特点:
在Web开发中,我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因。 React为此引入了虚拟DOM(Virtual DOM)的机制: 在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个虚拟DOM树,然后React将当前整个虚拟DOM树和上一次的虚拟DOM树进行对比,得到虚拟DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。 React Diff 算法虚拟DOM作为React的一大核心技术,了解其实现原理对于灵活应用有着很大帮助。 Javascript 虚拟DOM对象在我们项目中申明一个组件是这样的: react.createElement('div',null,[ // 创建一个img react.createElement('img',{ src: "avatar.png",class: "profile" }),// 或者 react.createElement('h1',[[user.firstName,user.lastName].join(' ')]) ]); 最后,React都会转换成类似这样的基本对象: { tagName: 'div',// 节点包含的属性 properties: { style: { color: '#fff' } },// 子节点 children: [],// 节点的唯一标识 key: 1 } Javascript DOM节点树然后,React把Javascript DOM模对象 转换成 Javascript DOM节点树: function create(vds,parent) { !Array.isArray(vds) && (vds = [vds]); // 如果没有父元素则创建个fragment来当父元素 parent = parent || document.createDocumentFragment(); var node; vds.forEach(function (vd) { // 如果是文字节点 if (isText(vd)) { // 创建文字节点 node = document.createTextNode(vd.text); } else { // 创建元素 node = document.createElement(vd.tag); } // 将元素塞入父容器 parent.appendChild(node); // 看看有没有子VNode,有孩子则处理孩子VNode vd.children && vd.children.length && create(vd.children,node); // 看看有没有属性,有则处理属性 vd.properties && setProps({ style: {} },vd.properties,node); }); return parent; } Diff现在我们得到的是Javascript 实现的虚拟DOM树,在一个事件循环中,当state或者preps变化时,React会创建一个新的虚拟DOM树,最后进行差异渲染。 diff(previous:VTree,current:VTree) -> PatchObject React分三种情景: 1. 分层对比
React 仅仅是尝试把树按照层级分解. 这彻底简化了复杂度,而且也不会失去很多,因为 Web 应用很少有 component 移动到树的另一个层级去。它们大部分只是在相邻的子节点之间移动。 2. 基于key匹配
Keys是一个VNode的唯一识别,用于对两个不同的VTree中的VNode做匹配的。通过key锁定某个组件后,React就可以直接对比这两个差异DOM节点树,复杂度为O(n)。 所以这里有个性能优化的技巧。假设你有一个key组件,他的key属性为foo,后续又将它改为bar,那么React就会掉过DOM diff,同时完全弃置div所有自元素,从头渲染。在渲染大型子树以避免diff计算时,这样的设计很有用,因为我们知道这种计算就是在浪费时间。 3. 基于自定义元素做优化
React提供自定义元素,所以匹配很简单。React 只会匹配相同 class 的 component。 比如,如果有个 结束React在你调用 component 的 setState 方法的时候,将其标记为 dirty,到每一个事件循环结束,React 检查所有标记 dirty 的 component 重新绘制。每次调用 setState 会重新计算整个子树.如果你想要提高性能,尽量少调用 setState。 最后,你还有可能去掉一些子树的重新渲染,如果你在 component 上实现function shouldComponentUpdate(nextProps,nextState) 的话,你根据 component 的前一个和下一个 props/state,告诉 React 这个 component 没有更新,也不需要重新绘制。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |