乐趣区

react的diff算法篇

对于 react 来说,diff 算法是里面最为重要的一个部分,它主要是用来提高 react 的重复渲染的效率,而本篇博客不会深入到 diff 算法的代码实现,只是讲述它的原理和策略。
传统的 Diff 算法:
如果将传统的 diff 算法和 v -dom 相结合,就会产生出复杂度为 O(nnn);所以如果要将 diff 算法和 v -dom 相结合,就必须优化 diff 算法;
由图可以看出,优化后的 diff 算法,复杂度只有 o(n),主要是因为 diff 结合了 v -dom 的特点进行优化,减少了不必要的比较。

传统的 diff 算法:https://neil.fraser.name/writ…
diff 算法的策略:
策略一:对于 dom 来说,跨层级节点的移动特别少,所以可以忽略,不用比较(应该没有谁会直接将父节点和子节点相交换吧);

策略二:对于由同一个类生成的两个组件,拥有相类似的树形结构(结构基本一样,值不一样),不同类生成的两个组件,他们的树形结构会完全不一样;
解读:由策略二,可以总结出四种类型的 rerender,第一种是相同类型的两个组件,他们的状态或者属性不一样,所以需要更新;第二种是新,旧两个组件是完全不同类型的组件,所以直接替换;第三种就是旧的存在,新的不存在,删除;第四种就是新的存在,旧的没有,增加;
策略三:同一层级的节点,可以有个唯一值区分($$type);
解读:只有同一层级的节点有唯一区分的值,那么在 rerender 时,才会标识为已存在,不用再渲染多一次。
对于以上三个策略,运用在 v -dom 中,从外到内运用,因此可以由 tree 到 component,再到 element 进行优化,利用(每一个组件都有很多 element,从而组成了组件的属性结构,再从而生成了更大的树形结构)

tree diff:
意义:任何一个大型的组件,都会转化层节点的结构树形态,所以一开始就比较两个结构树,会大大减少没必要的比较。
概念理解:对于两个节点结构树中的节点比较,如果这些节点所在的父节点不同,那么就没有必要比较,只有相同父节点的两个结构树,才有价值去比较里面的节点。
延伸:由 tree diff 可以延伸出对于组件的 component diff 和对于节点元素的 element diff 两种 diff 优化,这两种都遵循 diff 优化策略。
component diff:
如果比较的是组件类型,就可以如下图所示:

element diff:
由于元素节点是最小的单元,所以对于同一层级的元素节点,只存在三种行为:

增加节点;
删除节点;
移动节点;

对于更新,因为元素节点已经是最小的节点,所以对于更新,可以直接用增加和删除复合行为代替更新操作;
对于同一层级的节点来说,每个节点都应该要有属于自己的 key,key 在是用来辨别该节点是原本就在还是新增加的,这样一来可以提高的性能;
同一层级节点移动的优化顺序策略:

demo:
旧集合:A,B,C,D; 新集合:B,C,A,D

增加和删除节点:
demo:新集合的节点:A,C,D,E;旧集合的节点:B,D,C,A;

其实 diff 算法最终就是为了将新旧两个节点数进行对比,得出一个差异对象,然后根据这个差异对象,对 dom 进行操作。
diff 算法的目的就是为了对比新旧两个 v -dom,然后得出一个差异对象,最后根据差异对象来操作真实 dom,然后高效的 rerender 整个节点树。
因为归根到底,都是节点的操作,所以先从节点操作出发,节点的操作分为几类:插入,删除,移动。

这些图都是我在公司内网的 wiki 画好,所以直接截图(主要是懒得再画),以上就是我对 diff 算法的理解,理解的不全面,所以如果有不正确的地方,欢迎指出来。

退出移动版