React开始

一起来学React吧(2018.7.11——6)

    

本人已经入职,公司前端使用React,作为一名小白还是要从头学起。


React的diff算法

    学习了一周多的React,看了不少资料,基本上都在称赞它的虚拟Dom和牛掰的diff算法。今天花了大半天的时间看了diff相关的资料,这里整理了一点记录一下。
    再说React的diff算法之前,得先知道传统的diff是什么。传统的diff算法是用来转化树结构的,他要计算将一棵树转化为另一个不同结构树的步骤,并且实现转化。传统的diff做法就是,每个节点逐一比较。循环遍历所有的节点,执行插入,删除和移动操作。如果当前节点有子节点,按照这样的做法继续下去,至于何时会插入、合适删除和移动,需要一步步的判断,这里不深究。这样一直循环遍历,最后整个算法的时间复杂度达到了O(n^3),如果这样的算法移植到浏览器的DOM处理上,本来就很慢的DOM操作加上大量的DOM元素和n^3的复杂度,会对性能产生巨大的影响。
    React针对diff算法,做了大胆的假设策略,而这些策略在实际项目开发中,也确实如预期一样。

  1. tree diff——DOM节点跨层级操作少,基本可以忽略不计。

    这一个策略就可以使diff算法的时间复杂度从n^3下降到n。当diff忽略了跨层级移动节点的时候,就可只比较同一级的元素了,一旦节点发生变化也就是原节点不再的时候,不会再循环遍历它的子节点了,而是会删除整个子节点树。这样就可以对整个DOM节点数只遍历一次就能完成整个过程,时间复杂度也就降到了O(n)。(以上是我自己的理解,说的比较通俗,网上一大堆copy的解释文章写的对新人并不友好)当然也可能会出现跨层级的DOM操作,这时diff的做法就是当作原节点消失的方法,就是删除节点然后添加新的节点,这样可能会引起较大部分的DOM重新渲染,影响性能。所以React官方不建议进行跨DOM的节点操作。

  2. component diff——拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。(简单来说就是:如果不是同一个组件,基本上不会拥有相同的DOM结构)

    建立在这一假设上,diff可以在对同一级节点比较时直接比较节点类型。如果属于同一类型就安装传统的方法继续往下比较;如果不是同一类型,就判定当前组件为dirty component,从而替换整个组件下的所有子节点。对于相同类型的组件,可能存在Virtual DOM没有变化情况,如果能确切的知道哪些节点变化了可以节约diff的时间,所以React提供了shouldComponentUpdate()接口给用户,可以让coders手动判断组件是否需要进行diff。

  3. element diff——处于同一层级的节点,可以通过唯一的ID进行区分。

    这里的ID一般指的是用户设定的key值。在使用for、map等操作时,React经常会提醒warning报告说需要提供key值,而且ID(key)必须是唯一的,不能有相同的ID值,经常使用index、props.id等作为ID(key)值。在没有使用ID时,如果变化后的DOM只是在同一级进行了move操作,也就说没有数据变化,只有顺序变化,对于diff来说会像之前一样判断节点是否存在,如果消失则删除原节点然后添加新节点,对于这一点来说,diff会变得很不友好,原本Vertival DOM只是做了同级的移动操作,而diff却做了删除添加等操作。而当添加了ID之后,diff会判断相同的ID的节点是否存在,如果存在就保留,如果不存在就删除,如果有新ID的节点会添加进DOM树中。这样就减少了很多删除添加节点的时间,提供了diff算法的性能。所以针对这一点,React官方会在用户进行较多相同子节点创建的时候要求添加key值,这会极大的提升diff算法的性能。


以上所描述的是diff算法的思想,具体的实现是很复杂的。看源码看的满脸懵,主要是不清楚很多函数的作用。我们了解了diff算法之后,就可以跟着它的节奏去编写代码,尽量按着能提高性能方向去实现代码,不要让diff为难。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值