Jsx 表面写的是html,其实内部执行的是一段js
createElementhtml
React.createElement( type, [props], [...children] )
createElement把这个树形结构,存在内存里面
Jsx最终以这样的一个个对象递归的存在内存中,执行diff算法
多层结构react
简单的createElement实现算法
reactElement - 生成的是一个对象来描述这个节点dom
与传统树的diff的区别性能
计算一棵树形结构转换成另外一棵树形结构的最少操做,是一个复杂且值得研究的问题。传统 diff 算法经过循环递归对节点进行依次对比,效率低下,算法复杂度达到 O(n^3)优化
react diff策略spa
tree diffcode
基于策略一,对树进行分层比较,两棵树只会对同一层次的节点进行比较。 React 经过 updateDepth 对 Virtual DOM 树进行层级控制,同一个父节点下的全部子节点。
什么是 DOM 节点跨层级的移动操做?component
A 节点(包括其子节点)整个被移动到 D 节点下
若是出现了 DOM 节点跨层级的移动操做,React diff 会有怎样的表现呢?htm
React 只会简单的考虑同层级节点的位置变换,而对于不一样层级的节点,只有建立和删除操做。
当根节点发现子节点中 A 消失了,就会直接销毁 A;当 D 发现多了一个子节点 A,则会建立新的 A(包括子节点)做为其子节点。此时,React diff 的执行状况:create A -> create B -> create C -> delete A。
注意:
在开发组件时,保持稳定的 DOM 结构会有助于性能的提高。例如,能够经过 CSS 隐藏或显示节点,而不是真的移除或添加 DOM 节点。
component diff
依据策略二
React 判断 D 和 G 是不一样类型的组件,就不会比较两者的结构,而是直接删除 component D,从新建立 component G 以及其子节点,即便D 和 G的结构很类似
element diff
当节点处于同一层级时,React diff 提供了三种节点操做,分别为:INSERT_MARKUP(插入)、MOVE_EXISTING(移动)和 REMOVE_NODE(删除)。
eg: 新老集合进行 diff 差别化对比,发现 B != A,则建立并插入 B 至新集合,删除老集合 A;以此类推,建立并插入 A、D 和 C,删除 B、C 和 D。
带来的问题:都是相同的节点,但因为位置发生变化,致使须要进行繁杂低效的删除、建立操做,其实只要对这些节点进行位置移动便可
react优化策略:容许开发者对同一层级的同组子节点,添加惟一 key 进行区分
优化后diff实现:
分析:
element _mountIndex lastIndex nextIndex enqueueMove B 1 0 0 false A 0 1 1 true D 3 1 2 false C 2 3 3 true
step:
重新集合中取得 B,判断老集合中存在相同节点 B B 在老集合中的位置 B._mountIndex = 1 初始 lastIndex = 0 不知足 child._mountIndex < lastIndex 的条件,所以不对 B 进行移动操做 更新 lastIndex = Math.max(prevChild._mountIndex, lastIndex) lastIndex更新为1 将 B 的位置更新为新集合中的位置prevChild._mountIndex = nextIndex,此时新集合中 B._mountIndex = 0,nextIndex++
以上主要分析新老集合中存在相同节点但位置不一样时,对节点进行位置移动的状况,若是新集合中有新加入的节点且老集合存在须要删除的节点,那么 React diff 又是如何对比运做的呢?
element _mountIndex lastIndex nextIndex enqueueMove B 1 0 0 false E no exist C 2 1 2 false A 0 2 3 true
step
新建:重新集合中取得 E,判断老集合中不存在相同节点 E,则建立新节点 E lastIndex不作处理 E 的位置更新为新集合中的位置,nextIndex++ 删除:当完成新集合中全部节点 diff 时,最后还须要对老集合进行循环遍历,判断是否存在新集合中没有但老集合中仍存在的节点,发现存在这样的节点 D,所以删除节点 D
react diff的问题
理论上 diff 应该只需对 D 执行移动操做,然而因为 D 在老集合的位置是最大的,致使其余节点的 _mountIndex < lastIndex,形成 D 没有执行移动操做,而是 A、B、C 所有移动到 D 节点后面的现象
建议:在开发过程当中,尽可能减小相似将最后一个节点移动到列表首部的操做,当节点数量过大或更新操做过于频繁时,在必定程度上会影响 React 的渲染性能。
总结:
https://zhuanlan.zhihu.com/p/...