我的编程空间,编程开发者的网络收藏夹
学习永远不晚

React中的任务饥饿行为是什么意思

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

React中的任务饥饿行为是什么意思

本篇内容主要讲解“React中的任务饥饿行为是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React中的任务饥饿行为是什么意思”吧!

本文是在React中的高优先级任务插队机制基础上的后续延伸,先通过阅读这篇文章了解任务调度执行的整体流程,有助于更快地理解本文所讲的内容。

饥饿问题说到底就是高优先级任务不能毫无底线地打断低优先级任务,一旦低优先级任务过期了,那么他就会被提升到同步优先级去立即执行。如下面的例子:

我点击左面的开始按钮,开始渲染大量DOM节点,完成一次正常的高优先级插队任务:

React中的任务饥饿行为是什么意思

而一旦左侧更新的时候去拖动右侧的元素,并在拖动事件中调用setState记录坐标,介入更高优先级的任务,这个时候,左侧的DOM更新过程会被暂停,不过当我拖动到一定时间的时候,左侧的任务过期了,那它就会提升到同步优先级去立即调度,完成DOM的更新(低优先级任务的lane优先级并没有变,只是任务优先级提高了)。

React中的任务饥饿行为是什么意思

要做到这样,React就必须用一个数据结构去存储pendingLanes中有效的lane它对应的过期时间。另外,还要不断地检查这个lane是否过期。

这就涉及到了任务过期时间的记录 以及 过期任务的检查。

lane模型过期时间的数据结构

完整的pendingLanes有31个二进制位,为了方便举例,我们缩减位数,但道理一样。

例如现在有一个lanes:

0 b 0 0 1 1 0 0 0

那么它对应的过期时间的数据结构就是这样一个数组:

[ -1, -1, 4395.2254, 3586.2245, -1, -1, -1 ]

在React过期时间的机制中,-1 为 NoTimestamp

即pendingLanes中每一个1的位对应过期时间数组中一个有意义的时间,过期时间数组会被存到root.expirationTimes字段。这个计算和存取以及判断是否过期的逻辑

是在markStarvedLanesAsExpired函数中,每次有任务要被调度的时候都会调用一次。

记录并检查任务过期时间

在React中的高优先级任务插队机制那篇文章中提到过,ensureRootIsScheduled函数作为统一协调任务调度的角色,它会调用markStarvedLanesAsExpired函数,目的是把当前进来的这个任务的过期时间记录到root.expirationTimes,并检查这个任务是否已经过期,若过期则将它的lane放到root.expiredLanes中。

function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {   // 获取旧任务   const existingCallbackNode = root.callbackNode;    // 记录任务的过期时间,检查是否有过期任务,有则立即将它放到root.expiredLanes,   // 便于接下来将这个任务以同步模式立即调度   markStarvedLanesAsExpired(root, currentTime);    ...  }

markStarvedLanesAsExpired函数的实现如下:

暂时不需要关注suspendedLanes和pingedLanes

export function markStarvedLanesAsExpired(   root: FiberRoot,   currentTime: number, ): void {   // 获取root.pendingLanes   const pendingLanes = root.pendingLanes;   // suspense相关   const suspendedLanes = root.suspendedLanes;   // suspense的任务被恢复的lanes   const pingedLanes = root.pingedLanes;    // 获取root上已有的过期时间   const expirationTimes = root.expirationTimes;    // 遍历待处理的lanes,检查是否到了过期时间,如果过期,   // 这个更新被视为饥饿状态,并把它的lane放到expiredLanes    let lanes = pendingLanes;   while (lanes > 0) {            const index = pickArbitraryLaneIndex(lanes);     const lane = 1 << index;     // 上边两行的计算过程举例如下:     //   lanes = 0b0000000000000000000000000011100     //   index = 4      //       1 = 0b0000000000000000000000000000001     //  1 << 4 = 0b0000000000000000000000000001000      //    lane = 0b0000000000000000000000000001000      const expirationTime = expirationTimes[index];     if (expirationTime === NoTimestamp) {       // Found a pending lane with no expiration time. If it's not suspended, or       // if it's pinged, assume it's CPU-bound. Compute a new expiration time       // using the current time.       // 发现一个没有过期时间并且待处理的lane,如果它没被挂起,       // 或者被触发了,那么去计算过期时间       if (         (lane & suspendedLanes) === NoLanes ||         (lane & pingedLanes) !== NoLanes       ) {          expirationTimes[index] = computeExpirationTime(lane, currentTime);       }     } else if (expirationTime <= currentTime) {       // This lane expired       // 已经过期,将lane并入到expiredLanes中,实现了将lanes标记为过期       root.expiredLanes |= lane;     }     // 将lane从lanes中删除,每循环一次删除一个,直到lanes清空成0,结束循环     lanes &= ~lane;   } }

通过markStarvedLanesAsExpired的标记,过期任务得以被放到root.expiredLanes中在随后获取任务优先级时,会优先从root.expiredLanes中取值去计算优先级,这时得出的优先级是同步级别,因此走到下面会以同步优先级调度。实现过期任务被立即执行。

function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {   // 获取旧任务   const existingCallbackNode = root.callbackNode;    // 记录任务的过期时间,检查是否有过期任务,有则立即将它放到root.expiredLanes,   // 便于接下来将这个任务以同步模式立即调度   markStarvedLanesAsExpired(root, currentTime);    ...    // 若有任务过期,这里获取到的会是同步优先级   const newCallbackPriority = returnNextLanesPriority();    ...    // 调度一个新任务   let newCallbackNode;   if (newCallbackPriority === SyncLanePriority) {     // 过期任务以同步优先级被调度     newCallbackNode = scheduleSyncCallback(       performSyncWorkOnRoot.bind(null, root),     );   } }

记录并检查任务是否过期

concurrent模式下的任务执行会有时间片的体现,检查并记录任务是否过期就发生在每个时间片结束交还主线程的时候。可以理解成在整个(高优先级)任务的执行期间,

持续调用ensureRootIsScheduled去做这件事,这样一旦发现有过期任务,可以立马调度。

执行任务的函数是performConcurrentWorkOnRoot,一旦因为时间片中断了任务,就会调用ensureRootIsScheduled。

function performConcurrentWorkOnRoot(root) {    ...    // 去执行更新任务的工作循环,一旦超出时间片,则会退出renderRootConcurrent   // 去执行下面的逻辑   let exitStatus = renderRootConcurrent(root, lanes);    ...    // 调用ensureRootIsScheduled去检查有无过期任务,是否需要调度过期任务   ensureRootIsScheduled(root, now());    // 更新任务未完成,return自己,方便Scheduler判断任务完成状态   if (root.callbackNode === originalCallbackNode) {     return performConcurrentWorkOnRoot.bind(null, root);   }   // 否则retutn null,表示任务已经完成,通知Scheduler停止调度   return null; }

performConcurrentWorkOnRoot是被Scheduler持续执行的,这与Scheduler的原理相关,可以移步到我写的一篇长文帮你彻底搞懂React的调度机制原理这篇文章去了解一下,如果暂时不了解也没关系,你只需要知道它会被Scheduler在每一个时间片内都调用一次即可。

一旦时间片中断了任务,那么就会走到下面调用ensureRootIsScheduled。我们可以追问一下时间片下的fiber树构建机制,更深入的理解ensureRootIsScheduled

为什么会在时间片结束的时候调用。

这一切都要从renderRootConcurrent函数说起:

function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {    // workLoopConcurrent中判断超出时间片了,   // 那workLoopConcurrent就会从调用栈弹出,   // 走到下面的break,终止循环    // 然后走到循环下面的代码   // 就说明是被时间片打断任务了,或者fiber树直接构建完了   // 依据情况return不同的status   do {     try {       workLoopConcurrent();       break;     } catch (thrownValue) {       handleError(root, thrownValue);     }   } while (true);     if (workInProgress !== null) {       // workInProgress 不为null,说明是被时间片打断的       // return RootIncomplete说明还没完成任务     return RootIncomplete;   } else {      // 否则说明任务完成了

renderRootConcurrent中写了一个do...while(true)的循环,目的是如果任务执行的时间未超出时间片限制(一般未5ms),那就一直执行,

直到workLoopConcurrent调用完成出栈,brake掉循环。

workLoopConcurrent中依据时间片去深度优先构建fiber树

function workLoopConcurrent() {   // 调用shouldYield判断如果超出时间片限制,那么结束循环   while (workInProgress !== null && !shouldYield()) {     performUnitOfWork(workInProgress);   } }

所以整个持续检查过期任务过程是:一个更新任务被调度,Scheduler调用performConcurrentWorkOnRoot去执行任务,后面的步骤:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. performConcurrentWorkOnRoot调用renderRootConcurrent,renderRootConcurrent去调用workLoopConcurrent执行fiber的构建任务,也就是update引起的更新任务。

  3. 当执行时间超出时间片限制之后,首先workLoopConcurrent会弹出调用栈,然后renderRootConcurrent中的do...while(true)被break掉,使得它也弹出调用栈,因此回到performConcurrentWorkOnRoot中。

  4. performConcurrentWorkOnRoot继续往下执行,调用ensureRootIsScheduled检查有无过期任务需要被调度。

  5. 本次时间片跳出后的逻辑完成,Scheduler会再次调用performConcurrentWorkOnRoot执行任务,重复1到3的过程,也就实现了持续检查过期任务。

总结

低优先级任务的饥饿问题其实本质上还是高优先级任务插队,但是低优先级任务在被长时间的打断之后,它的优先级并没有提高,提高的根本原因是markStarvedLanesAsExpired

将过期任务的优先级放入root.expiredLanes,之后优先从expiredLanes获取任务优先级以及渲染优先级,即使pendingLanes中有更高优先级的任务,但也无法从pendingLanes中

获取到高优任务对应的任务优先级。

到此,相信大家对“React中的任务饥饿行为是什么意思”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

React中的任务饥饿行为是什么意思

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Linux服务器中的drupal是什么意思

这篇文章给大家介绍Linux服务器中的drupal是什么意思,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。DrupalDrupal为用户提供各种工具来管理网站,它可以帮助用户入门,建立自己的网站 1、下载drup
2023-06-05

JavaScript中的宏任务和微任务执行顺序是什么

这篇“JavaScript中的宏任务和微任务执行顺序是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript
2023-07-04

服务器托管中的U是什么意思

本篇内容主要讲解“服务器托管中的U是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“服务器托管中的U是什么意思”吧!1、为什么要规定服务器的尺寸之所以要规定服务器的尺寸,是为了使托管服务器
2023-06-07

服务器租用中的U是什么意思

本篇内容主要讲解“服务器租用中的U是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“服务器租用中的U是什么意思”吧!服务器租用中的U代表什么:“U”在服务器领域中特指机架式服务器厚度,是一
2023-06-07

云服务器中1核指的是什么意思

这篇文章主要介绍云服务器中1核指的是什么意思,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!云服务器的1核是指什么?云服务器的1核是指云服务器CPU配置1核。CPU是服务器的中央处理器,是衡量服务器性能的重要指标。一般
2023-06-14

亚马逊服务器使用的linux发行版是什么意思

亚马逊服务器使用的Linux发行版是指亚马逊公司在其云计算服务AmazonWebServices(AWS)上提供的Linux操作系统。AWS提供了多种不同的Linux发行版,包括AmazonLinux、RedHatEnterpriseLinux、SUSELinuxEnterpriseServer、UbuntuServer等。这些发行版都是经过优化和定制的,以适应亚马逊的云计算环境和客户需求。用户可以选择他们喜欢的Linux发行版来运行他们的应用程序和服务。
2023-10-27

华为云服务器账号密码是什么意思呀怎么设置的

通常,服务器的账号密码需要通过登录华为云服务器控制台进行设置。在登录之前,您需要先创建一个华为云服务器账号并输入相应的登录信息。具体而言,您需要提供服务器的用户名、密码和其他必要的信息,例如您的主机名、IP地址、用户名和密码等等。在登录华为云服务器控制台时,您可以使用以下步骤进行设置:输入服务器的用户名和密码。用户名和
2023-10-27

华为云服务器登录密码是什么意思呀怎么设置的

1.什么是华为云服务器登录密码?华为云服务器登录密码是您登录华为云服务器时所需的密码。它用于验证您的身份,并确保只有授权的用户可以访问服务器。2.如何设置华为云服务器登录密码?您可以按照以下步骤设置华为云服务器登录密码:步骤1:登录华为云控制台首先,打开您的浏览器,访问华为云官方网站,并点击登录按钮。输入您的华为云账号和密码,然后点击登录。步骤2:选择云服务器在华为云控制台的首页,点击左侧导航栏中的“云...
2023-10-27

华为云服务器账号密码是什么意思啊怎么设置的

在华为云控制台中进入服务器主页面。点击“登录”按钮进入登录页面。在登录页面中输入您的华为云服务器账号和密码,并点击“登录”按钮。输入您的账号和密码后,点击“登录”按钮。成功登录后,在登录页面中找到您的服务器和配置文件,如图所示。在配置文件中,您需要修改一些用户名和密码。在修改完用户名和密码后,您需要点击“确定”按钮保存
华为云服务器账号密码是什么意思啊怎么设置的
2023-10-28

在云服务器上进行编程开发的方法是什么意思

云服务器是一种基于云计算技术的虚拟服务器,可以通过互联网进行访问和管理。在云服务器上进行编程开发,意味着开发人员可以使用云服务器提供的计算资源和服务来进行软件开发、测试和部署等工作。这种方法可以带来许多好处,例如:灵活性:云服务器可以根据需要进行扩展或缩减,可以根据项目需求来选择适当的计算资源和服务。可靠性:云服务器通常具有高可用性和容错性,可以保证应用程序的稳定性和可靠性。安全性:云服
2023-10-26

编程语言中任务调度的并行算法是什么

编程语言中任务调度的并行算法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。如果给定一批任务,比如有500个任务,需要在尽可能快的时间内做完。如果串行是肯定不行的。我们
2023-06-02

MySQL 中的事务是什么意思?解释一下它的属性?

事务是一组按顺序执行的数据库操作,就像是一个单一的工作单元。换句话说,除非组内的每个操作都成功,否则事务将永远不会完成。如果事务中的任何操作失败,整个事务将失败。实际上,我们可以将许多SQL查询组合成一组,并将它们作为事务的一部分一起执行。
2023-10-22

华为云服务器登录界面怎么设置的密码是什么意思

用户名和密码是华为云服务器的登录凭据,用于验证用户身份,确保服务器安全可靠。用户名和密码的设置应该简单易记,容易被记忆。为了保护用户名和密码的安全,华为云服务器提供了多种安全机制,如密码长度限制、密码复杂度、双因素认证等。用户需要在登录时通过输入正确的用户名和密码、提供正确的用户名和密码和身份验证码等多种方式,确保登录
华为云服务器登录界面怎么设置的密码是什么意思
2023-10-28

服务器中用户并发数已满指的是什么意思

小编给大家分享一下服务器中用户并发数已满指的是什么意思,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!用户并发数已满的意思就是同时登录的用户太多了;用户在访问或者下
2023-06-25

编程热搜

目录