这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

为什么在使用前会发生帧丢失

如何理解浏览器中的框架

是什么 它解决了什么问题

有什么好处

它是如何工作的

源代码分析

当我们学习任何东西时,我们必须经历两个阶段。一是这是什么东西 第二,这东西做什么 在介绍之前,让我们先谈谈我们以前遇到的问题,对于这个问题,我们可以自己编写一个简单的渲染过程模拟。

我们已经了解到,虚拟对象是包含节点类型和属性的对象。我们假设我们有以下信息,现在我们需要使用自定义方法将其呈现到页面:

事实上,创建、操作和递归处理子元素有三个步骤。

从这段代码中,您应该能够想到一个问题。假设我们的结果非常复杂,递归渲染肯定非常耗时;这段代码是同步执行的,因此一旦递归开始,就无法停止。

每个人都知道浏览器是单线程的,并且线程到线程是独占的,因此假设此代码运行足够长,浏览器将不得不等待,在严重的情况下,浏览器可能不会响应。

当然,团队中的人员太多,渲染不会严重延迟,但在极端情况下,渲染大量节点时仍会出现帧丢失问题。这种现象可以与光纤与堆栈演示后引入的渲染差异进行比较:

显然,在引入概念和重构后,渲染过程非常流畅。

即使现在我们还不了解,但通过了解传统的递归渲染,我们知道同步渲染需要一个线层,你可以解决这个问题,我们可以猜测将有一个类似的线程控制操作,但在介绍之前,我们仍然介绍了浏览器框架的概念,以及为什么会出现框架下降的情况,这将有助于我们的理解,所以让我们继续讨论。

所以回到浏览器渲染,我们也可以理解浏览器动画变成图片,主流监视器的刷新率实际上是60帧/秒,也就是说,第二个屏幕将高速刷新60次,根据计算机的设置,那么帧预算时间实际上就是。

告诉浏览器您希望执行动画,并要求浏览器在下次重画之前通过调用指定的回调函数来更新动画。此方法需要传入回调函数,该函数将在浏览器下次重画之前执行。

我们可以用一个简单的例子来检验这一结论,而不仅仅是这样说:

如果希望在本地运行此示例,可以看到该方法执行的每个帧的接受开始时间差为零。如果时差较小,则使用刷新率较高的计算机监视器。

我们人眼的视觉帧是在舒适放松的时候,也就是说,1s必须至少有24帧。我们可以认为图片处理,但也可以说,在以前的版本中处理,渲染任务只要太长就会始终占用线程,导致浏览器渲染任务延迟,如果浏览器渲染1s之间的延迟甚至不低于60帧,浏览器渲染的总帧速率将自然降低,我们的视觉直觉是,该帧将被删除。

所以这里我们解释了帧丢失的根本原因,传统的递归调用堆栈实现,在长任务前面会导致线程占用,严重的会是帧丢失,需要另一种策略来解决这个问题,让我们来谈谈。

那么如何理解呢,分两个层次来解释:

在操作机制方面,它是一种进程放弃机制,可以中断中的同步渲染,并将渲染控制权交还给浏览器,从而达到不阻塞浏览器渲染的目的。

从数据的角度来看,可以细化为数据结构或执行单元。

我们可以将两者结合起来理解,将运行后的一个执行单元测试自己还剩多少时间,如果有时间,将继续运行,反之亦然,将中止并记录任务,同时将返回到浏览器控件,直到下一次浏览器本身完成工作,有空闲时间,将一次又一次地进行控制。

传统递归,一种变黑的方法

,灵活性放弃了控制以确保渲染和浏览器响应

至于数据结构,正如我在文章中简要提到的,每个创建的现实都被包装为一个节点,该节点具有以下结构:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

这种设计的优点是在数据层中描述了不同节点之间的关系。即使任务终止,当执行下一个恢复任务时,此结构也有助于恢复任务站点,并知道下一步应处理哪些节点。

当然,上面的摘要只是为了说明它是什么。从组合的角度来看,一般来说,它具有以下核心特征:

支持增量渲染,在每个帧中拆分渲染任务。不是一口气全部渲染,停下来再继续渲染,没有时间先暂停

支持暂停、终止和恢复以前的渲染任务。

通过优先处理不同的任务。放置高优先级操作,如事件交互响应、页面呈现等,如网络请求等

支持并发处理结合对第3点的理解,面对可变的任务堆,始终以最高优先级处理,灵活调整处理顺序,以确保在允许的最短时间内响应重要任务,而不是考虑顺序

在这一点上,我相信你的头脑中有一个模糊的理解,也许有些学生很好奇如何做到这一点来放弃控制 你怎么知道下一步该做什么 然后我们得介绍另一个。

方法插入一个函数,该函数将在浏览器空闲时调用。这使开发人员能够在主事件循环上执行后台和低优先级工作,而不会影响关键事件如动画和输入响应的延迟。

类似地,它也可以接受一个参数,而这个参数反过来又可以接受浏览器告诉您还有多少时间执行。让我们看一个简单的例子:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

简单地说,当浏览器有空闲时间时,会自动调用此方法,浏览器会告诉您还有多少时间。

因此,我们可以把一些不太重要或优先级较低的事情留在那里,然后决定我们是否有时间去做。当我们有时间做我们需要做的事情时,当我们决定不做时,控制自然会回到浏览器,因为浏览器不是空闲的,因为JS没有任何事情可做。那么我们如何计算剩余时间呢

从上面我们知道,所谓的帧丢弃是指,通常情况下,浏览器可以在1秒内渲染60帧,但由于线程总是被占用,浏览器的响应时间不足以渲染这么多次,因此1秒渲染的帧总数相对较低,这就是我们所称的帧丢弃。一般来说,1帧时间是,这是一种表示吗

这是真的,但重要的是要注意,在某些极端情况下,浏览器会给我们最空闲的时间去做我们想做的事情,比如我们的一些任务非常耗时,浏览器知道我们会去做,但为了让页面呈现不太卡顿,同时要照顾好线程,所以它会从上升到一个帧,这意味着1S浏览器此时最多可以渲染20帧。

我们可以使用以下代码有意创建一个耗时的场景,然后检查剩余时间:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

如您所见,第一次输出的剩余时间仍然非常小,但在第一个任务结束时有一个耗时的逻辑,因此浏览器只提到1帧的剩余时间,以及为什么它实际上与性能相关,如下所示:

延迟时间

用户感知

0-16ms

非常顺利

0-100ms

基本流程

100-1000ms

你可以感觉到一些延迟

1000ms或更大

失去耐心

再见,再也不要来了

这是在保持浏览器响应性和在不可能的情况下保持刷新外观之间的折衷。

因此,考虑到这一点,我们知道如何放弃控制权是很重要的。

然而,应当指出的是,在最终实施中并没有直接采用。一方面,它仍处于实验阶段,兼容性不是很好。其次,考虑到剩余时间只有20帧左右,体验仍然不是很好。所以我是通过自己的模拟来实现的。

上面我们介绍了在绘制每个帧之前浏览器将调用的,因此您要做的事情将被放入,并且可以接受浏览器传递的帧的开始时间,因此您开始计算帧和帧之间的时间差,以判断它是否超出预期时间。这部分知识我个人觉得有些超类,如果你感兴趣,可以直接搜索这个关键词,这里不会模拟实现过程。

协调阶段:这个阶段做很多事情,比如在这个阶段创建比较等等。比较完成后,等待下一次提交。请注意,此阶段可以暂停。

提交阶段:在协调阶段计算的更改一次提交。这个阶段是同步的,不间断的。

因此,我将向您展示节点是如何创建的,它们是如何比较的,以及其余时间是如何从源角度工作的。

为了更好地理解以下源代码,我使用以下组件作为模板:

在虚拟节点准备就绪后,将基于虚拟节点创建节点,因此这里我们将解释如何创建节点以及如何建立兄弟关系。

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

根据上图,可以发现这实际上是一组处于一定遍历级别的所有子元素,然后依次遍历子元素以调用方法来获取节点。在较低级别,通过让子元素。

您可以在方法末尾看到返回,通过让父对象知道其第一个子对象是谁来建立父子关系。因此,这里有兄弟关系,以及父对象的第一个子对象如何建立。

那么你是如何创建它的呢 我们继续跟踪该方法:

我们在前面的方法中提到了如何设置兄弟节点以及如何将第一个子节点绑定到父节点。通俗地说,从父节点的角度来看,mine仅用于绑定第一个子节点,子节点本身将与父节点建立关系。在这里,我们已经清楚地解释了这三个字段,然后我们遵循调用过程:

这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法:

如您所见,我们终于找到了构造函数,我们通过调用它得到了一个实例。因此,在这里,我们清楚地了解了节点创建过程,以及节点网络是如何建立的。

事实上,使用节点的另一个原因是通过该网络模拟传统的调用堆栈。你为什么这么说 上面还说,传统的调用堆栈一旦启动就无法停止,而列表的一个很好的好处是,我甚至暂停了,还可以通过设置提前恢复下一次的节点单元,一旦浏览器有空闲时间,我们仍然可以快速恢复以前的工作,再次是父兄之间的关系,上下文可以自然地再次形成,可以想象,节点对于恢复以前的工作具有重要意义。

阅读源代码后,我发现这是协调阶段的一部分。更新组件时,它将比较现有节点和新的虚拟节点,如果存在差异,则更新节点。所以在这里,我将站在源代码的角度来看它是如何完成的。

为了更容易理解这里发生了什么,我将把结构放在这里,但它实际上看起来像这样。

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

因此,更新的起点实际上是一个代表组件的节点,它指向组件内部的节点。比较过程也是通过链表递归的,递归过程依赖于以下两种方法:

您可以在方法中看到的判断是,只要节点不为空,就继续递归调用该方法。

从上面可以看出,只要子节点仍然存在,链表的概念就会不断更新和给出。因此,它还验证了即使任务暂停,也可以继续先前的工作。

现在,我们单击的组件的更新按钮将改变其状态,并将其从当前组件向下重新命名为根节点,因此起点,即上图中的起点,我们将跳过额外的递归,我们将在方法语句中结束,这是组件实际开始更新的地方。

接下来,由于组件将再次渲染,因此将调用组件以获取虚拟节点信息:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

接下来我们来谈谈方法:

做一件非常简单的事情,就是看看是否存在,第一次渲染肯定不存在,所以会采取挂载的路线,我们之前分析过的创建过程实际上是要走的。

因为我们正在更新,所以它必须存在。然后我们传递旧节点和新虚拟节点,我们可以看到中间节点已经更新:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

方法将确定新节点是否是什么类型,例如当前的us是虚拟的,它是一个对象,因此将继续调用一个方法,根据递归的属性,稍后还将进行对比,即包含2个数组,因此下一轮将调用方法,在这里提前打招呼,然后我们来看方法:

事实上,确实如此。如果你看看我添加的评论,下面是对过程的简要描述:

检查现有节点是否存在。如果否,则创建安装逻辑。

有一个解释是旧的,然后比较,如果不相等,直接运行,即从旧的父节点的节点,整个将被删除,子节点不需要比较,这也验证了逐步比较,父节点不同,子节点不同。

如果它是一样的,它是旧的和新的。如果不同,就不一样了。您调用该方法并将自己从旧父级中完全删除。

如果它们相同,则它们已更改,因此调用该方法以根据新节点更新旧节点。

你做的很清楚。使用旧节点和新虚拟节点创建一个新节点。创建过程的代码与之前相同,此处未显示。

当它完成后,它会返回,它会给你新的设置,父节点,等等,所以在这里就完成了。代码将返回到这句话,一直返回到的赋值。这是什么意思

前面的比较,其实是站在更新完成的角度,还有自己的子节点,所以接下来认为父节点依次更新其三个子节点,还记得前面我们说过的吗 然后执行以下操作:

在创建阶段对该方法进行了部分分析,其逻辑是直接重新创建现有方法,因为没有现有方法。在这种情况下,由于我们有一个现有的方法,我们将不重新创建现有的方法而是执行以下代码:

同样,源代码如下:

这与前面的比较逻辑相同。这是相同的比较,因此我们使用该方法,顾名思义,该方法根据新虚拟对象的属性更新旧节点:

做一件非常简单的事情,确定是否有一个旧节点,有相同的调用,将旧节点从新节点中取出,而不是重新创建。

我不知道你是否注意到,即使我们显式地做了很多条件判断,即使如此,我们仍然在底层某处做底层处理,所以代码看起来很多,事实上,大部分是为了逻辑健壮性。

很清楚在那之后你要做什么,更新并考虑是否更新,显然他们没有,所以代码终于回来了,没有任务单元可以执行,所以协调阶段已经完成。

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

因为它是最高优先级的,所以一旦浏览器允许,最终创建的内容将被重新更新到页面上,我不会在这里显示代码过程。

因此,我们在这里介绍了帧的概念,解释了渲染速度慢的许多原因。

然后我们有,那是什么 在较小的层次上,它是一种包含任务开始时间、节点关系信息的数据结构,如果我们稍微看高一点,我们也可以说它是一个模拟调用堆栈的特殊链表,以解决传统调用堆栈无法暂停的问题。

从宏观角度来看,它是一种调度传输机制,实现了增量渲染的目的,并在浏览器有剩余时间时始终以最高优先级完成任务,同时确保帧数平滑。

因此,如果我要细化关键词,我会给出以下几点:

这是一种数据结构。

使用父子关系和魔术,以链表的形式模拟传统的调用堆栈。

是一种调度放弃机制,仅在剩余时间时运行。

实现增量渲染,根据浏览器允许拼接最终渲染。

并发性是通过为任务分配不同的优先级来实现的,确保在有时间时始终执行最高优先级,而不是占位符。

协调和承诺分为两个阶段。协调包括创建和更新,可以挂起。提交必须同步,以确保渲染不会延迟。

通过协调阶段,我们了解对比过程,如果结构被理解为一棵树,那么这个过程本质上是一个深度遍历,按照父亲-父亲的第一个孩子-和每个孩子的兄弟的顺序。

通过源代码,我们知道是同一层的比较,第一次比较,如果不一样,那么就不比较直接删除剩下的节点,这也强调了比较的重要性,第二次将比较元素和。事实上,此比较过程是将旧虚拟机与新虚拟机进行比较,而不是与虚拟机或虚拟机与虚拟机进行对比。事实上,这并不难理解。如果它们相同,则意味着只使用简单的替换,而不是完全重建,这从性能角度来看更为有利。

最后,附上更新计划的执行程序:

 这个方法实际上什么都不做,它只是虚拟地提取元素类型及其相关属性,然后调用该方法: 热门话题

手动rip React光纤源代码

这可能是打开React Fiber最常用的方法

反应纤维原理

深入研究纤维


发表评论

Copyright 2002-2022 by 茜申时尚百货品牌网(琼ICP备2022001899号-3).All Rights Reserved.