当前位置: 首页 > 科技观察

React中的任务饥饿行为

时间:2023-03-12 08:39:18 科技观察

本文是基于React中高优先级任务队列机制的后续扩展。首先,阅读本文了解任务调度和执行的整体流程,有助于您更快地理解演讲内容。归根结底,饥饿问题就是高优先级任务不能无底线打断低优先级任务。一旦低优先级任务到期,它会被提升为同步优先级立即执行。如下例:我点击左边的开始按钮,开始渲染大量DOM节点,完成一个普通的高优先级跳队任务:左边更新完毕,拖动右边的元素,调用它在拖动事件setState中记录坐标并干预更高优先级的任务。这时候左边的DOM更新进程会被挂起,但是当我拖到某个时候,左边的任务过期了,那么就会提升为同步优先级,立即调度完成DOM的更新(低优先级任务的车道优先级没有变化,但任务优先级增加了)。为此,React必须使用一种数据结构将有效通道对应的过期时间存储在pendingLanes中。此外,还需要不断检查车道是否已过期。这涉及到任务过期时间的记录和过期任务的检查。车道模型过期时间数据结构完整。pendingLanes有31个二进制数字。为了示例方便,我们减少了位数,但是原理是一样的。比如现在有一个泳道:0b0011000,那么它对应的过期时间的数据结构就是这样一个数组:[-1,-1,4395.2254,3586.2245,-1,-1,-1]在React的机制中expirationtime,-1表示NoTimestamp,即pendingLanes中的每个1位对应expirationtime数组中一个有意义的时间,过期时间数组会存储在root.expirationTimes字段中。过期的计算、获取和判断逻辑在markStarvedLanesAsExpired函数中,每次调度任务时都会调用该函数。记录并查看任务过期时间。在React中的高优先级任务队列机制一文中提到,ensureRootIsScheduled函数起到统一协调任务调度的作用。它将调用markStarvedLanesAsExpired函数使当前传入的任务过期。记录时间到root.expirationTimes,检查task是否过期,如果过期,将其lane放在root.expiredLanes中。functionensureRootIsScheduled(root:FiberRoot,currentTime:number){//获取旧任务constexistingCallbackNode=root.callbackNode;//记录任务的过期时间,检查是否有过期任务,立即放入root.expiredLanes,//方便接下来以同步方式立即调度这个任务。markStarvedLanesAsExpired(root,currentTime);...}markStarvedLanesAsExpired函数的实现如下:暂时不用关注suspendedLanes和pingedLanesexport函数markStarvedLanesAsExpired(root:FiberRoot,currentTime:number,):void{//getroot.pendingLanesconstpendingLanes=root.pendingLanes;//suspense相关constsuspendedLanes=root.suspendedLanes;//suspense任务resumedlanesconstpingedLanes=root.pingedLanes;//获取root上已有的过期时间constexpirationTimes=root.expirationTimes;//遍历待处理的lanes,检查是否到了过期时间,如果过期,//本次更新视为饥饿状态,将其lane放入expiredLanesletlanes=pendingLanes;while(lanes>0){/*pickArbitraryLaneIndex是寻找laneslanes中最左边1的index是获取expirationTimes中当前lane对应的index,比如0b0010,获取到的index为2,则可以去expirationtimes获取index为2的位置的过期时间*/constindex=pickArbitraryLaneIndex(lanes);constlane=1<