项目 2022-07-04 00:43 作者:baidu    浏览:128    

1213309-20220703165700777-2072041167.png

我是什么是fiber? fiber解决了什么问题? 从源代码的角度详细介绍fiber的运行机制和diff的运行,文章描述了处理的协调和提交两个阶段,并在讨论协调时介绍了另一个重要的概念。 那么,既然我们提到了,顺便问一下另一个有趣的概念吧。 那么,现在来问一下大家吧。 你怎么理解,有什么用呢? 想想怎么回答。

我想很多人有时会说在数组前添加元素等,作为标签发挥作用。 通过明确知道只添加一个节点,其他两个节点可以直接复用,可以大幅优化性能。

就像官网介绍时的例子一样:

如果子元素具有key,React将使用key将原始树的子元素与最新树的子元素相匹配。 以下示例在添加后使以前的低效率转换变得高效。

现在,React知道只有拥有key的元素是新元素,只有拥有的元素和key的元素移动了。

那么这个回答有问题吗? 官方是这么说的。 那个恐怕没有问题。 但是,如果我是面试官的话,我会基于这个回答提出以下问题。

渲染时如果我们不提供就会发出警告,为什么不提供普通的结构却不会呢? 谈谈你的理解。

里面真的这么聪明吗? 渲染列表时,我可以知道哪些是新添加的,哪些是可以直接重用的吗?

我们知道的是每个阶层的比较,假设现在有:个序列

我们更新后如下

根据逐层比较的概念,应该是:

1213309-20220703165828483-1744093495.png

你不是觉得那个每次比较都不一样吗? 是否需要在比较所有层后重新渲染? 优化是怎么做的呢?

根据逐层比较的逻辑,如果新旧节点的值相等,则证明这个旧节点是可复用的。 如果我们不提供,默认为; 你还要逐层比较,为了这个时候的东西,可以复用,那为什么需要提供独一无二的东西呢?

为什么不推荐,理由是什么?

通过这五个问题,可以看出其实官方基于的说明其实是一个特别宏观的视角。 如果你知道一点源代码,你也会知道公式这个结论还经不起推敲。 那么,带着这些问题投身到源代码中,通过这些问题重新理解吧。

老实说,上述我提出的五个问题的结论其实是相互关联和依赖的,所以在解释这些问题之前,我要得出两个比较核心的结论:

新旧节点对非结构的对比确实是逐层对比,但对结构,假设添加了独特的东西时则未必如此。

比较器先比较,不同时直接重新创建节点,相同时重新比较,不同时重新创建; 因此,只有在所有情况都相同时,才会基于旧节点联接生成新节点。

首先请记住这两个结论。 接下来继续说明结论和上述问题。

站在设计的角度,结合我对源代码的理解,谈谈我的意见。

我们知道的节点总是动态生成的,每次数据更改时都需要生成新的列表。 从角度来看,必须考虑数据的大小是否会成为性能问题。 因此,在源代码级别,如果和相同,则使用旧节点的数据创建新节点,而不是重新创建新节点。

结构有时用于缓存旧节点,便于后续比较。 高速缓存的逻辑如下。

1213309-20220703165853799-2096591862.png

但是,请注意,结构并不利用缓存中的旧节点。 经过测试,只有在唯一且不同的情况下,缓存逻辑才会触发,如下所示:

在第一次比较中,我想你的孩子是不是在数组之前或数组中间插入了新元素,所以为了不使逐层比较重新创建下一个节点,这时跳出前面的逻辑,来到方法,把旧节点放进去,然后借用

以下示例在数组之后插入元素。 这就是为什么它永远不会到达缓存逻辑。 也就是说,比较起来是一样的。 之后的判断可能只是新旧节点不同,所以直接复用更新即可。 不需要缓存。

所以,来临时,结构基本稳定,很难遇到插入新节点的场面。 更多的变化是模板语法的变量和其他样式,因此也不需要用来存储这些变化不大的节点。

而且,从性能优化的角度来看,第一个最大的禁忌是早期的过度优化。 想想看。 还可以用,那些不提供你拿来保存吗? 嗯,是的如何知道谁是谁? 你强硬地规定需要提供一切吗? 此外,即使强制开发人员提供了所有节点,由于必须考虑内存使用和内存泄漏问题,您也会发现这样的设计非常不合理。

总之,相对于不易出现非结构频繁变动的情况,逐层比较满足新旧节点比较的需要,而结构数据频繁变动,在头部和中部插入新数据后,会出现逐层对比度错位失效的情况,导致旧节点

假设对于公式给出的示例,在数组之前添加了元素。 因为只要增加一个就能知道其他只是移动了位置的结论,所以有必要考虑初学者,考虑强调的作用,所以在说明上看起来非常聪明,但实际上并不是这样。

不能因为相同就断定旧节点只是移动了。 最容易推翻这个结论的例子是相同但不同的。 例如,以下内容:

前面的过程中也说过,与某种情况相比,租用旧节点来缓存,所以它起到了一个标识的作用。 比较结束后,还是需要比较是否相同。 即使是一样的,也不能保证是否一样。 如果你走到这一步,一定或者任何一个发生了变化,一定要更新节点。 当然,不存在在过程中直接完全复用旧节点的说法。

官方只是旧节点移动了,实际上存在一定的误解,源代码级别不合逻辑,但重新创建的成本相对较小。

关于第三个问题,如上所述,针对的未必是分层的,如果没有提供或者提供,前后节点的一贯性就会变得相等,继续判断是否更新旧节点进行复用。

如果对比不同,则首先声明一个,然后使用它依次缓存旧节点,然后根据新的虚拟节点顺序,通过以后获取旧节点,看能否获取就相同,依次判断能否更新旧节点中描述的场景,使用以下步骤创建明细表,以便在概念设计中分析体量的体积。

毕竟,确实起到了标记的作用,但我们知道,该标记多以数组开头或数组中途插入新数据的场景为对象,只要不同,就无法按层次继续比较。 否则,所有下一个肯定的内容都将是不同的,并且将被新创建,因此可以基于独一无二的基础上创建旧的内容,从而更新原来的比较顺序被插入打乱的旧节点。

以下是在数组开头插入新元素时的部分源代码。 请结合插入数组开头的例子来理解。

例如,我们在数组前填充了新节点。 在最初的对比中,外面发现这又是数组的逻辑。 所以,在数组的前面或中间插入元素,推测会因此而不同。 因此,将调用预先保存旧存储。

结合例子,此时的为3个虚拟,依次扫描,与返回的节点进行比较并更新。 接下来,我们来看看:

使用这种方法也很简单,当您确定新节点的类型为数字或字符串时,将转至更新文本的方法,反之亦然。 在对象更新中,我们看到的逻辑将通过获取旧节点,然后通过进行进一步更新。

那么,我们看了对能否获取旧节点的各种处理。 例如,因为明显找不到,所以会变成yes。 因此,用以下方法完全重新制作。

如果为或,则为旧节点的更新逻辑,而不是重新创建,因为它是以前的旧节点。

其实说到这里,我想大家应该也对这个问题有一定程度的了解。 对非结构来说,是否确实提供并不重要,反正大家都是层层比较; 另外,当存在数组报头和中间插入要素时,无论假设大家提供还是不提供,新旧节点都将相等。 这将已经偏移的节点强行按每个阶层进行对比,由于应该重新制作的节点相同而被更新,导致应该被更新的节点以相同的结果成为新节点。

理由用第四个问题回答了。 而且,核心的问题是,应该是新的结果,因为你只做了更新。 这种情况有时也会导致这种情况。 虽然官方也给出了原因的例子,但是让我们结合源代码详细调查一下为什么使用它吧。

示例的代码如下所示。

简单来说,我们使用各自和独一无二的行为。 而且,我们分别属于两个中的第一个一个值。 然后,单击按钮,在每个数组的前面插入了新数据。 然后,差异出现了。 的例子并没有像期待的那样完全重新制作一个。 这本来应该属于第二个。

那么为什么会发生这个呢? 原因其实很简单,使用行为的时候,正如前文所述,这个应该重新制作。 毕竟,你用了,为了,又一样。 所以,我直接认为这不是重塑,而是更新。

在虚拟这篇文章中,我们强调了虚拟为局部创新提供了可能性。 由于原生属性非常多,递归对比起来显得格外复杂,但虚拟设计集中在需要直接对比的属性上,更新后也只是更新虚拟,如上述文章所示,其本身就是原生属性,根本不在比较范畴之内

如上所述,因为您似乎只是更新了,所以节点具有包含相应真实属性的字段。 因此,对于节点,将以前的赋值直接提供给更新后的节点,从而它仍然保留在第一个节点上。

1213309-20220703165946439-1370173418.png

上图是第一次更新完成后访问的。 因此,这是原因。

在数组之前插入元素时,使用缺省值和不使用缺省值之间的唯一区别将在两个图中进行说明。

1213309-20220703170005536-1399005099.png

1213309-20220703170011418-702138534.png

至此,我已经说明了开头的5个问题,还有用源代码解开的神秘面纱。 简而言之,它并不像大家想象的那么聪明,但它对我来说至关重要。正因为它始终保持着层层对比,存在着,所以无论怎么排序,它也是独一无二的,它始终能够准确地更新和新建,这是它存在的核心意义。

那么,关于的介绍到此结束。


 
打赏