react源码层分析协调与调度_第1页
react源码层分析协调与调度_第2页
react源码层分析协调与调度_第3页
react源码层分析协调与调度_第4页
react源码层分析协调与调度_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第react源码层分析协调与调度目录requestEventTimerequestUpdateLanefindUpdateLanelanePriorityLanePrioritycreateUpdateenqueueUpdate总结协调与调度reconciler流程同步任务类型执行机制异步任务类型执行机制shouldYieldperformUnitOfWorkbeginWorkcompleteUnitOfWorkscheduler流程performWorkUntilDeadline总结

requestEventTime

其实在React执行过程中,会有数不清的任务要去执行,但是他们会有一个优先级的判定,假如两个事件的优先级一样,那么React是怎么去判定他们两谁先执行呢?

//packages/react-reconciler/src/ReactFiberWorkLoop.old.js

exportfunctionrequestEventTime(){

if((executionContext(RenderContext|CommitContext))!==NoContext){

//We'reinsideReact,soit'sfinetoreadtheactualtime.

//react事件正在执行

//executionContext

//RenderContext正在计算

//CommitContext正在提交

//exportconstNoContext=/**/0b0000000;

//constBatchedContext=/**/0b0000001;

//constEventContext=/**/0b0000010;

//constDiscreteEventContext=/**/0b0000100;

//constLegacyUnbatchedContext=/**/0b0001000;

//constRenderContext=/**/0b0010000;

//constCommitContext=/**/0b0100000;

//exportconstRetryAfterError=/**/0b1000000;

returnnow();

//没有在react事件执行NoTimestamp===-1

if(currentEventTime!==NoTimestamp){

//浏览器事件正在执行,返回上次的currentEventTime

returncurrentEventTime;

//重新计算currentEventTime,当执行被中断后

currentEventTime=now();

returncurrentEventTime;

}

RenderContext与CommitContext表示正在计算更新和正在提交更新,返回now()。如果是浏览器事件正在执行中,返回上一次的currentEventTime。如果终止或者中断react任务执行的时候,则重新获取执行时间now()。获取的时间越小,则执行的优先级越高。

now()并不是单纯的newDate(),而是判定两次更新任务的时间是否小于10ms,来决定是否复用上一次的更新时间Scheduler_now的。

exportconstnow=initialTimeMs10000Scheduler_now:()=Scheduler_now()-initialTimeMs;

其实各位猜想一下,对于10ms级别的任务间隙时间,几乎是可以忽略不计的,那么这里就可以视为同样的任务,不需要有很大的性能开销,有利于批量更新。

requestUpdateLane

requestEventTime位每一个需要执行的任务打上了触发更新时间标签,那么任务的优先级还需要进一步的确立,requestUpdateLane就是用来获取每一个任务执行的优先级的。

//packages/react-reconciler/src/ReactFiberWorkLoop.old.js

exportfunctionrequestUpdateLane(fiber:Fiber):Lane{

//Specialcases

constmode=fiber.mode;

if((modeBlockingMode)===NoMode){

return(SyncLane:Lane);

}elseif((modeConcurrentMode)===NoMode){

returngetCurrentPriorityLevel()===ImmediateSchedulerPriority

(SyncLane:Lane)

:(SyncBatchedLane:Lane);

}elseif(

!deferRenderPhaseUpdateToNextBatch

(executionContextRenderContext)!==NoContext

workInProgressRootRenderLanes!==NoLanes

//Thisisarenderphaseupdate.Thesearenotofficiallysupported.The

//oldbehavioristogivethisthesame"thread"(expirationtime)as

//whateveriscurrentlyrendering.Soifyoucall`setState`onacomponent

//thathappenslaterinthesamerender,itwillflush.Ideally,wewantto

//removethespecialcaseandtreatthemasiftheycamefroman

//interleavedevent.Regardless,thispatternisnotofficiallysupported.

//Thisbehaviorisonlyafallback.Theflagonlyexistsuntilwecanroll

//outthesetStatewarning,sinceexistingcodemightaccidentallyrelyon

//thecurrentbehavior.

returnpickArbitraryLane(workInProgressRootRenderLanes);

//Thealgorithmforassigninganupdatetoalaneshouldbestableforall

//updatesatthesameprioritywithinthesameevent.Todothis,theinputs

//tothealgorithmmustbethesame.Forexample,weusethe`renderLanes`

//toavoidchoosingalanethatisalreadyinthemiddleofrendering.

//However,the"included"lanescouldbemutatedinbetweenupdatesinthe

//sameevent,likeifyouperformanupdateinside`flushSync`.Oranyother

//codepaththatmightcall`prepareFreshStack`.

//Thetrickweuseistocachethefirstofeachoftheseinputswithinan

//event.Thenresetthecachedvaluesoncewecanbesuretheeventisover.

//Ourheuristicforthatiswheneverweenteraconcurrentworkloop.

//We'lldothesamefor`currentEventPendingLanes`below.

if(currentEventWipLanes===NoLanes){

currentEventWipLanes=workInProgressRootIncludedLanes;

constisTransition=requestCurrentTransition()!==NoTransition;

if(isTransition){

if(currentEventPendingLanes!==NoLanes){

currentEventPendingLanes=

mostRecentlyUpdatedRoot!==null

mostRecentlyUpdatedRoot.pendingLanes

:NoLanes;

returnfindTransitionLane(currentEventWipLanes,currentEventPendingLanes);

//TODO:RemovethisdependencyontheSchedulerpriority.

//Todothat,we'rereplacingitwithanupdatelanepriority.

//获取执行任务的优先级,便于调度

constschedulerPriority=getCurrentPriorityLevel();

//TheoldbehaviorwasusingthepriorityleveloftheScheduler.

//ThiscouplesReacttotheSchedulerinternals,sowe'rereplacingit

//withthecurrentUpdateLanePriorityabove.Asanexampleofhowthis

//couldbeproblematic,ifwe'renotinside`Scheduler.runWithPriority`,

//thenwe'llgetthepriorityofthecurrentrunningSchedulertask,

//whichisprobablynotwhatwewant.

letlane;

if(

//TODO:Temporary.We'reremovingtheconceptofdiscreteupdates.

(executionContextDiscreteEventContext)!==NoContext

//用户block的类型事件

schedulerPriority===UserBlockingSchedulerPriority

//通过findUpdateLane函数重新计算lane

lane=findUpdateLane(InputDiscreteLanePriority,currentEventWipLanes);

}else{

//根据优先级计算法则计算lane

constschedulerLanePriority=schedulerPriorityToLanePriority(

schedulerPriority,

if(decoupleUpdatePriorityFromScheduler){

//Inthenewstrategy,wewilltrackthecurrentupdatelanepriority

//insideReactandusethatprioritytoselectalaneforthisupdate.

//Fornow,we'rejustloggingwhenthey'redifferentsowecanassess.

constcurrentUpdateLanePriority=getCurrentUpdateLanePriority();

if(

schedulerLanePriority!==currentUpdateLanePriority

currentUpdateLanePriority!==NoLanePriority

if(__DEV__){

console.error(

'Expectedcurrentschedulerlanepriority%stomatchcurrentupdatelanepriority%s',

schedulerLanePriority,

currentUpdateLanePriority,

//根据计算得到的schedulerLanePriority,计算更新的优先级lane

lane=findUpdateLane(schedulerLanePriority,currentEventWipLanes);

returnlane;

}

通过getCurrentPriorityLevel获得所有执行任务的调度优先级schedulerPriority。通过findUpdateLane计算lane,作为更新中的优先级。

findUpdateLane

exportfunctionfindUpdateLane(

lanePriority:LanePriority,wipLanes:Lanes,

):Lane{

switch(lanePriority){

caseNoLanePriority:

break;

caseSyncLanePriority:

returnSyncLane;

caseSyncBatchedLanePriority:

returnSyncBatchedLane;

caseInputDiscreteLanePriority:{

constlane=pickArbitraryLane(InputDiscreteLanes~wipLanes);

if(lane===NoLane){

//Shifttothenextprioritylevel

returnfindUpdateLane(InputContinuousLanePriority,wipLanes);

returnlane;

caseInputContinuousLanePriority:{

constlane=pickArbitraryLane(InputContinuousLanes~wipLanes);

if(lane===NoLane){

//Shifttothenextprioritylevel

returnfindUpdateLane(DefaultLanePriority,wipLanes);

returnlane;

caseDefaultLanePriority:{

letlane=pickArbitraryLane(DefaultLanes~wipLanes);

if(lane===NoLane){

//Ifallthedefaultlanesarealreadybeingworkedon,lookfora

//laneinthetransitionrange.

lane=pickArbitraryLane(TransitionLanes~wipLanes);

if(lane===NoLane){

//Allthetransitionlanesaretaken,too.Thisshouldbevery

//rare,butasalastresort,pickadefaultlane.Thiswillhave

//theeffectofinterruptingthecurrentwork-in-progressrender.

lane=pickArbitraryLane(DefaultLanes);

returnlane;

caseTransitionPriority://ShouldbehandledbyfindTransitionLaneinstead

caseRetryLanePriority://ShouldbehandledbyfindRetryLaneinstead

break;

caseIdleLanePriority:

letlane=pickArbitraryLane(IdleLanes~wipLanes);

if(lane===NoLane){

lane=pickArbitraryLane(IdleLanes);

returnlane;

default:

//Theremainingprioritiesarenotvalidforupdates

break;

invariant(

false,

'Invalidupdatepriority:%s.ThisisabuginReact.',

lanePriority,

}

相关参考视频讲解:进入学习

lanePriorityLanePriority

exportopaquetypeLanePriority=

|10

|11

|12

|13

|14

|15

|16

|17;

exportopaquetypeLanes=number;

exportopaquetypeLane=number;

exportopaquetypeLaneMapT=ArrayT

import{

ImmediatePriorityasImmediateSchedulerPriority,

UserBlockingPriorityasUserBlockingSchedulerPriority,

NormalPriorityasNormalSchedulerPriority,

LowPriorityasLowSchedulerPriority,

IdlePriorityasIdleSchedulerPriority,

NoPriorityasNoSchedulerPriority,

}from'./SchedulerWithReactIntegration.new';

//同步任务

exportconstSyncLanePriority:LanePriority=15;

exportconstSyncBatchedLanePriority:LanePriority=14;

//用户事件

constInputDiscreteHydrationLanePriority:LanePriority=13;

exportconstInputDiscreteLanePriority:LanePriority=12;

constInputContinuousHydrationLanePriority:LanePriority=11;

exportconstInputContinuousLanePriority:LanePriority=10;

constDefaultHydrationLanePriority:LanePriority=9;

exportconstDefaultLanePriority:LanePriority=8;

constTransitionHydrationPriority:LanePriority=7;

exportconstTransitionPriority:LanePriority=6;

constRetryLanePriority:LanePriority=5;

constSelectiveHydrationLanePriority:LanePriority=4;

constIdleHydrationLanePriority:LanePriority=3;

constIdleLanePriority:LanePriority=2;

constOffscreenLanePriority:LanePriority=1;

exportconstNoLanePriority:LanePriority=0;

createUpdate

exportfunctioncreateUpdate(eventTime:number,lane:Lane):Update*{

constupdate:Update*={

eventTime,//更新时间

lane,//优先级

tag:UpdateState,//更新

payload:null,//需要更新的内容

callback:null,//更新完后的回调

next:null,//指向下一个更新

returnupdate;

}

createUpdate函数入参为eventTime和lane,输出一个update对象,而对象中的tag表示此对象要进行什么样的操作。

exportconstUpdateState=0;//更新

exportconstReplaceState=1;//替换

exportconstForceUpdate=2;//强制更新

exportconstCaptureUpdate=3;//xx更新

createUpdate就是单纯的给每一个任务进行包装,作为一个个体推入到更新队列中。

enqueueUpdate

exportfunctionenqueueUpdateState(fiber:Fiber,update:UpdateState){

//获取当前更新队列?为啥呢?因为无法保证react是不是还有正在更新或者没有更新完毕的任务

constupdateQueue=fiber.updateQueue;

//如果更新队列为空,则表示fiber还未渲染,直接退出

if(updateQueue===null){

//Onlyoccursifthefiberhasbeenunmounted.

return;

constsharedQueue:SharedQueueState=(updateQueue:any).shared;

constpending=sharedQueue.pending;

if(pending===null){

//Thisisthefirstupdate.Createacircularlist.

//还记得那个更新对象吗?update.next=

//如果pedding位null,表示第一次渲染,那么他的指针为update本身

update.next=update;

}else{

//将update插入到更新队列循环当中

update.next=pending.next;

pending.next=update;

sharedQueue.pending=update;

if(__DEV__){

if(

currentlyProcessingQueue===sharedQueue

!didWarnUpdateInsideUpdate

console.error(

'Anupdate(setState,replaceState,orforceUpdate)wasscheduled'+

'frominsideanupdatefunction.Updatefunctionsshouldbepure,'+

'withzeroside-effects.ConsiderusingcomponentDidUpdateora'+

'callback.',

didWarnUpdateInsideUpdate=true;

}

这一步就是把需要更新的对象,与fiber更新队列关联起来。

总结

React通过获取事件的优先级,处理具有同样优先级的事件,创建更新对象并与fiber的更新队列关联起来。到这一步updateContainer这个流程就走完了,也下面就是开始他的协调阶段了。

协调与调度

协调与调度的流程大致如图所示:

reconciler流程

React的reconciler流程以scheduleUpdateOnFiber为入口,并在checkForNestedUpdates里面处理任务更新的嵌套层数,如果嵌套层数过大(50),就会认为是无效更新,则会抛出异常。之后便根据markUpdateLaneFromFiberToRoot对当前的fiber树,自底向上的递归fiber的lane,根据lane做二进制比较或者位运算处理。详情如下:

如果当前执行任务的优先级为同步,则去判断有无正在执行的React任务。如果没有则执行ensureRootIsScheduled,进行调度处理。如果当前任务优先级是异步执行,则执行ensureRootIsScheduled进行调度处理。

exportfunctionscheduleUpdateOnFiber(

fiber:Fiber,lane:Lane,eventTime:number,

//检查嵌套层数,避免是循环做无效操作

checkForNestedUpdates();

warnAboutRenderPhaseUpdatesInDEV(fiber);

//更新当前更新队列里面的任务优先级,自底而上更新child.fiberLanes

constroot=markUpdateLaneFromFiberToRoot(fiber,lane);

if(root===null){

warnAboutUpdateOnUnmountedFiberInDEV(fiber);

returnnull;

//Markthattheroothasapendingupdate.

//标记root有更新的,执行它

markRootUpdated(root,lane,eventTime);

if(root===workInProgressRoot){

//Receivedanupdatetoatreethat'sinthemiddleofrendering.Mark

//thattherewasaninterleavedupdateworkonthisroot.Unlessthe

//`deferRenderPhaseUpdateToNextBatch`flagisoffandthisisarender

//phaseupdate.Inthatcase,wedon'ttreatrenderphaseupdatesasif

//theywereinterleaved,forbackwardscompatreasons.

if(

deferRenderPhaseUpdateToNextBatch||

(executionContextRenderContext)===NoContext

workInProgressRootUpdatedLanes=mergeLanes(

workInProgressRootUpdatedLanes,

lane,

if(workInProgressRootExitStatus===RootSuspendedWithDelay){

//Therootalreadysuspendedwithadelay,whichmeansthisrender

//definitelywon'tfinish.Sincewehaveanewupdate,let'smarkitas

//suspendednow,rightbeforemarkingtheincomingupdate.Thishasthe

//effectofinterruptingthecurrentrenderandswitchingtotheupdate.

//TODO:Makesurethisdoesn'toverridepingsthathappenwhilewe've

//alreadystartedrendering.

markRootSuspended(root,workInProgressRootRenderLanes);

//TODO:requestUpdateLanePriorityalsoreadsthepriority.Passthe

//priorityasanargumenttothatfunctionandthisone.

//获取当前优先级层次

constpriorityLevel=getCurrentPriorityLevel();

//同步任务,采用同步更新的方式

if(lane===SyncLane){

if(

//Checkifwe'reinsideunbatchedUpdates

(executionContextLegacyUnbatchedContext)!==NoContext

//Checkifwe'renotalreadyrendering

(executionContext(RenderContext|CommitContext))===NoContext

//Registerpendinginteractionsontheroottoavoidlosingtracedinteractiondata.

//同步而且没有react任务在执行,调用performSyncWorkOnRoot

schedulePendingInteractions(root,lane);

//Thisisalegacyedgecase.TheinitialmountofaReactDOM.render-ed

//rootinsideofbatchedUpdatesshouldbesynchronous,butlayoutupdates

//shouldbedeferreduntiltheendofthebatch.

performSyncWorkOnRoot(root);

}else{

//如果有正在执行的react任务,那么执行它ensureRootIsScheduled去复用当前正在执行的任务

//跟本次更新一起进行

ensureRootIsScheduled(root,eventTime);

schedulePendingInteractions(root,lane);

if(executionContext===NoContext){

//Flushthesynchronousworknow,unlesswe'realreadyworkingorinside

//abatch.ThisisintentionallyinsidescheduleUpdateOnFiberinsteadof

//scheduleCallbackForFibertopreservetheabilitytoscheduleacallback

//withoutimmediatelyflushingit.Weonlydothisforuser-initiated

//updates,topreservehistoricalbehavioroflegacymode.

resetRenderTimer();

flushSyncCallbackQueue();

}else{

//Scheduleadiscreteupdatebutonlyifit'snotSync.

//如果此次是异步任务

if(

(executionContextDiscreteEventContext)!==NoContext

//Onlyupdatesatuser-blockingpriorityorgreaterareconsidered

//discrete,eveninsideadiscreteevent.

(priorityLevel===UserBlockingSchedulerPriority||

priorityLevel===ImmediateSchedulerPriority)

//Thisistheresultofadiscreteevent.Trackthelowestpriority

//discreteupdateperrootsowecanflushthemearly,ifneeded.

if(rootsWithPendingDiscreteUpdates===null){

rootsWithPendingDiscreteUpdates=newSet([root]);

}else{

rootsWithPendingDiscreteUpdates.add(root);

//Scheduleotherupdatesafterincasethecallbackissync.

//可以中断更新,只要调用ensureRootIsScheduled=performConcurrentWorkOnRoot

ensureRootIsScheduled(root,eventTime);

schedulePendingInteractions(root,lane);

//Weusethiswhenassigningalaneforatransitioninside

//`requestUpdateLane`.Weassumeit'sthesameastherootbeingupdated,

//sinceinthecommoncaseofasinglerootappitprobablyis.Ifit'snot

//thesameroot,thenit'snotahugedeal,wejustmightbatchmorestuff

//togethermorethannecessary.

mostRecentlyUpdatedRoot=root;

}

同步任务类型执行机制

当任务的类型为同步任务,并且当前的js主线程空闲,会通过performSyncWorkOnRoot(root)方法开始执行同步任务。

performSyncWorkOnRoot里面主要做了两件事:

renderRootSync从根节点开始进行同步渲染任务commitRoot执行commit流程

当前js线程中有正在执行的任务时候,就会触发ensureRootIsScheduled函数。ensureRootIsScheduled里面主要是处理当前加入的更新任务的lane是否有变化:

如果没有变化则表示跟当前的schedule一起执行。如果有则创建新的schedule。调用performSyncWorkOnRoot执行同步任务。

functionensureRootIsScheduled(root:FiberRoot,currentTime:number){

constexistingCallbackNode=root.callbackNode;

//Checkifanylanesarebeingstarvedbyotherwork.Ifso,markthemas

//expiredsoweknowtoworkonthosenext.

markStarvedLanesAsExpired(root,currentTime);

//Determinethenextlanestoworkon,andtheirpriority.

constnextLanes=getNextLanes(

root,

root===workInProgressRootworkInProgressRootRenderLanes:NoLanes,

//Thisreturnstheprioritylevelcomputedduringthe`getNextLanes`call.

constnewCallbackPriority=returnNextLanesPriority();

if(nextLanes===NoLanes){

//Specialcase:There'snothingtoworkon.

if(existingCallbackNode!==null){

cancelCallback(existingCallbackNode);

root.callbackNode=null;

root.callbackPriority=NoLanePriority;

return;

//Checkifthere'sanexistingtask.Wemaybeabletoreuseit.

if(existingCallbackNode!==null){

constexistingCallbackPriority=root.callbackPriority;

if(existingCallbackPriority===newCallbackPriority){

//Thepriorityhasn'tchanged.Wecanreusetheexistingtask.Exit.

return;

//Theprioritychanged.Canceltheexistingcallback.We'llscheduleanew

//onebelow.

cancelCallback(existingCallbackNode);

//Scheduleanewcallback.

letnewCallbackNode;

if(newCallbackPriority===SyncLanePriority){

//Specialcase:SyncReactcallbacksarescheduledonaspecial

//internalqueue

//同步任务调用performSyncWorkOnRoot

newCallbackNode=scheduleSyncCallback(

performSyncWorkOnRoot.bind(null,root),

}elseif(newCallbackPriority===SyncBatchedLanePriority){

newCallbackNode=scheduleCallback(

ImmediateSchedulerPriority,

performSyncWorkOnRoot.bind(null,root),

}else{

//异步任务调用performConcurrentWorkOnRoot

constschedulerPriorityLevel=lanePriorityToSchedulerPriority(

newCallbackPriority,

newCallbackNode=scheduleCallback(

schedulerPriorityLevel,

performConcurrentWorkOnRoot.bind(null,root),

root.callbackPriority=newCallbackPriority;

root.callbackNode=newCallbackNode;

}

所以任务类型为同步的时候,不管js线程空闲与否,都会走到performSyncWorkOnRoot,进而走renderRootSync、workLoopSync流程,而在workLoopSync中,只要workInProgressfiber不为null,则会一直循环执行performUnitOfWork,而performUnitOfWork中会去执行beginWork和completeWork,也就是上一章里面说的beginWork流程去创建每一个fiber节点

//packages/react-reconciler/src/ReactFiberWorkLoop.old.js

functionworkLoopSync(){

while(workInProgress!==null){

performUnitOfWork(workInProgress);

}

异步任务类型执行机制

异步任务则会去执行performConcurrentWorkOnRoot,进而去执行renderRootConcurrent、workLoopConcurrent,但是与同步任务不同的是异步任务是可以中断的,这个可中断的关键字就在于shouldYield,它本身返回值是一个false,为true则可以中断。

//packages/react-reconciler/src/ReactFiberWorkLoop.old.js

functionworkLoopConcurrent(){

while(workInProgress!==null!shouldYield()){

performUnitOfWork(workInProgress);

}

每一次在执行performUnitOfWork之前都会关注一下shouldYield()返回值,也就是说的reconciler过程可中断的意思。

shouldYield

//packages\scheduler\src\SchedulerPostTask.js

exportfunctionunstable_shouldYield(){

returngetCurrentTime()=deadline;

}

getCurrentTime为newDate(),deadline为浏览器处理每一帧结束时间戳,所以这里表示的是,在浏览器每一帧空闲的时候,才会去处理此任务,如果当前任务在浏览器执行的某一帧里面,则会中断当前任务,等待浏览器当前帧执行完毕,等到下一帧空闲的时候,才会去执行当前任务。

所以不管在workLoopConcurrent还是workLoopSync中,都会根据当前的workInProgressfiber是否为null来进行循环调用performUnitOfWork。根据流程图以及上面说的这一些,可以看得出来从beginWork到completeUnitOfWork这个过程究竟干了什么。

这三章将会讲解fiber树的reconcileChildren过程、completeWork过程、commitMutationEffectsinsertOrAppendPlacementNodeIntoContainer(DOM)过程。这里将详细解读v17版本的React的diff算法、虚拟dom到真实dom的创建,函数生命钩子的执行流程等。

performUnitOfWork

functionperformUnitOfWork(unitOfWork:Fiber):void{

//Thecurrent,flushed,stateofthisfiberisthealternate.Ideally

//nothingshouldrelyonthis,butrelyingonitheremeansthatwedon't

//needanadditionalfieldontheworkinprogress.

constcurrent=unitOfWork.alternate;

setCurrentDebugFiberInDEV(unitOfWork);

letnext;

if(enableProfilerTimer(unitOfWork.modeProfileMode)!==NoMode){

startProfilerTimer(unitOfWork);

next=beginWork(current,unitOfWork,subtreeRenderLanes);

stopProfilerTimerIfRunningAndRecordDelta(unitOfWork,true);

}else{

//beginWork

next=beginWork(current,unitOfWork,subtreeRenderLanes);

resetCurrentDebugFiberInDEV();

unitOfWork.memoizedProps=unitOfWork.pendingProps;

if(next===null){

//Ifthisdoesn'tspawnnewwork,completethecurrentwork.

//completeUnitOfWork

completeUnitOfWork(unitOfWork);

}else{

workInProgress=next;

ReactCurrentOwner.current=null;

}

所以在performUnitOfWork里面,每一次执行beginWork,进行workIngProgress更新,当遍历完毕整棵fiber树之后便会执行completeUnitOfWork。

beginWork

我们可以看到beginWork就是originBeginWork得实际执行。我们翻开beginWork的源码可以看到,它便是根据不同的workInProgress.tag执行不同组件类型的处理函数,这里就不去拆分的太细,只有有想法便会单独出一篇文章讲述这个的细节,但是最后都会去调用reconcileChildren。

completeUnitOfWork

当遍历完毕执行beginWork,遍历完毕之后就会走completeUnitOfWork。

functioncompleteUnitOfWork(unitOfWork:Fiber):void{

//Attempttocompletethecurrentunitofwork,thenmovetothenext

//sibling.Iftherearenomoresiblings,returntotheparentfiber.

letcompletedWork=unitOfWork;

do{

//Thecurrent,flushed,stateofthisfiberisthealternate.Ideally

//nothingshouldrelyonthis,butrelyingonitheremeansthatwedon't

//needanadditionalfieldontheworkinprogress.

constcurrent=completedWork.alternate;

constreturnFiber=completedWork.return;

//Checkiftheworkcompletedorifsomethingthrew.

if((completedWork.flagsIncomplete)===NoFlags){

setCurrentDebugFiberInDEV(completedWork);

letnext;

if(

!enableProfilerTimer||

(completedWork.modeProfileMode)===NoMode

//绑定事件,更新props,更新dom

next=completeWork(current,completedWork,subtreeRenderLanes);

}else{

startProfilerTimer(completedWork);

next=completeWork(current,completedWork,subtreeRenderLanes);

//Updaterenderdurationassumingwedidn'terror.

stopProfilerTimerIfRunningAndRecordDelta(completedWork,false);

resetCurrentDebugFiberInDEV();

if(next!==null){

//Completingthisfiberspawnednewwork.Workonthatnext.

workInProgress=next;

return;

resetChildLanes(completedWork);

if(

returnFiber!==null

//Donotappendeffectstoparentsifasiblingfailedtocomplete

(returnFiber.flagsIncomplete)===NoFlags

//Appendalltheeffectsofthesubtreeandthisfiberontotheeffect

//listoftheparent.Thecompletionorderofthechildrenaffectsthe

//side-effectorder.

//把已收集到的副作用,合并到父级effectlists中

if(returnFiber.firstEffect===null){

returnFiber.firstEffect=completedWork.firstEffect;

if(completedWork.lastEffect!==null){

if(returnFiber.lastEffect!==null){

returnFiber.lastEffect.nextEffect=completedWork.firstEffect;

returnFiber.lastEffect=completedWork.lastEffect;

//Ifthisfiberhadside-effects,weappenditAFTERthechildren's

//side-effects.Wecanperformcertainside-effectsearlierifneeded,

//bydoingmultiplepassesovertheeffectlist.Wedon'twantto

//scheduleourownside-effectonourownlistbecauseifendup

//reusingchildrenwe'llschedulethiseffectontoitselfsincewe're

//attheend.

constflags=completedWork.flags;

//SkipbothNoWorkandPerformedWorktagswhencreatingtheeffect

//list.PerformedWorkeffectisreadbyReactDevToolsbutshouldn'tbe

//committed.

//跳过NoWork,PerformedWork在commit阶段用不到

if(flagsPerformedWork){

if(returnFiber.lastEffect!==null){

returnFiber.lastEffect.nextEffect=completedWork;

}else{

returnFiber.firstEffect=completedWork;

returnFiber.lastEffect=completedWork;

}else{

//Thisfiberdidnotcompletebecausesomethingthrew.Popvaluesoff

//thestackwithoutenteringthecompletephase.Ifthisisaboundary,

//capturevaluesifpossible.

constnext=unwindWork(completedWork,subtreeRenderLanes);

//Becausethisfiberdidnotcomplete,don'tresetitsexpirationtime.

if(next!==null){

//Ifcompletingthisworkspawnednewwork,dothatnext.We'llcome

//backhereagain.

//Sincewe'rerestarting,removeanythingthatisnotahosteffect

//fromtheeffecttag.

next.flags=HostEffectMask;

workInProgress=next;

return;

if(

enableProfilerTimer

(completedWork.modeProfileMode)!==NoMode

//Recordtherenderdurationforthefiberthaterrored.

stopProfilerTimerIfRunningAndRecordDelta(completedWork,false);

//Includethetimespentworkingonfailedchildrenbeforecontinuing.

letactualDuration=completedWork.actualDuration;

letchild=completedWork.child;

while(child!==null){

actualDuration+=child.actualDuration;

child=child.sibling;

completedWork.actualDuration=actualDuration;

if(returnFiber!==null){

//Marktheparentfiberasincompleteandclearitseffectlist.

returnFiber.firstEffect=returnFiber.lastEffect=null;

returnFiber.flags|=Incomplete;

//兄弟层指针

constsiblingFiber=completedWork.sibling;

if(siblingFiber!==null){

//IfthereismoreworktodointhisreturnFiber,dothatnext.

workInProgress=siblingFiber;

return;

//Otherwise,returntotheparent

completedWork=returnFiber;

//Updatethenextthingwe'reworkingonincasesomethingthrows.

workInProgress=completedWork;

}while(completedWork!==null);

//We'vereachedtheroot.

if(workInProgressRootExitStatus===RootIncomplete){

workInProgressRootExitStatus=RootCompleted;

}

他的作用便是逐层收集fiber树上已经被打上的副作用标签flags,一直收集到root上面以便于在commit阶段进行dom的增删改。

scheduler流程

在这里应该有很多人不明白,协调和调度是什么意思,通俗来讲:

协调就是协同合作调度就是执行命令

所以在React中协调就是一个js线程中,需要安排很多模块去完成整个流程,例如:同步异步lane的处理,reconcileChildren处理fiber节点等,保证整个流程有条不紊的执行。调度表现为让空闲的js线程(帧层面)去执行其他任务,这个过程称之为调度,那么它到底是怎么去做的呢?

我们回到处理异步任务那里,我们会发现performConcurrentWorkOnRoot这个函数外面包裹了一层scheduleCallback:

newCallbackNode=scheduleCallback(

schedulerPriorityLevel,

performConcurrentWorkOnRoot.bind(null,root),

)

exportfunctionscheduleCallback(

reactPriorityLevel:ReactPriorityLevel,callback:SchedulerCallback,options:SchedulerCallbackOptions|void|null,

constpriorityLevel=reactPriorityToSchedulerPriority(reactPriorityLevel);

returnScheduler

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论