react源碼層分析協(xié)調(diào)與調(diào)度_第1頁(yè)
react源碼層分析協(xié)調(diào)與調(diào)度_第2頁(yè)
react源碼層分析協(xié)調(diào)與調(diào)度_第3頁(yè)
react源碼層分析協(xié)調(diào)與調(diào)度_第4頁(yè)
react源碼層分析協(xié)調(diào)與調(diào)度_第5頁(yè)
已閱讀5頁(yè),還剩28頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第react源碼層分析協(xié)調(diào)與調(diào)度目錄requestEventTimerequestUpdateLanefindUpdateLanelanePriorityLanePrioritycreateUpdateenqueueUpdate總結(jié)協(xié)調(diào)與調(diào)度reconciler流程同步任務(wù)類型執(zhí)行機(jī)制異步任務(wù)類型執(zhí)行機(jī)制shouldYieldperformUnitOfWorkbeginWorkcompleteUnitOfWorkscheduler流程performWorkUntilDeadline總結(jié)

requestEventTime

其實(shí)在React執(zhí)行過(guò)程中,會(huì)有數(shù)不清的任務(wù)要去執(zhí)行,但是他們會(huì)有一個(gè)優(yōu)先級(jí)的判定,假如兩個(gè)事件的優(yōu)先級(jí)一樣,那么React是怎么去判定他們兩誰(shuí)先執(zhí)行呢?

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

exportfunctionrequestEventTime(){

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

//We'reinsideReact,soit'sfinetoreadtheactualtime.

//react事件正在執(zhí)行

//executionContext

//RenderContext正在計(jì)算

//CommitContext正在提交

//exportconstNoContext=/**/0b0000000;

//constBatchedContext=/**/0b0000001;

//constEventContext=/**/0b0000010;

//constDiscreteEventContext=/**/0b0000100;

//constLegacyUnbatchedContext=/**/0b0001000;

//constRenderContext=/**/0b0010000;

//constCommitContext=/**/0b0100000;

//exportconstRetryAfterError=/**/0b1000000;

returnnow();

//沒有在react事件執(zhí)行NoTimestamp===-1

if(currentEventTime!==NoTimestamp){

//瀏覽器事件正在執(zhí)行,返回上次的currentEventTime

returncurrentEventTime;

//重新計(jì)算currentEventTime,當(dāng)執(zhí)行被中斷后

currentEventTime=now();

returncurrentEventTime;

}

RenderContext與CommitContext表示正在計(jì)算更新和正在提交更新,返回now()。如果是瀏覽器事件正在執(zhí)行中,返回上一次的currentEventTime。如果終止或者中斷react任務(wù)執(zhí)行的時(shí)候,則重新獲取執(zhí)行時(shí)間now()。獲取的時(shí)間越小,則執(zhí)行的優(yōu)先級(jí)越高。

now()并不是單純的newDate(),而是判定兩次更新任務(wù)的時(shí)間是否小于10ms,來(lái)決定是否復(fù)用上一次的更新時(shí)間Scheduler_now的。

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

其實(shí)各位猜想一下,對(duì)于10ms級(jí)別的任務(wù)間隙時(shí)間,幾乎是可以忽略不計(jì)的,那么這里就可以視為同樣的任務(wù),不需要有很大的性能開銷,有利于批量更新。

requestUpdateLane

requestEventTime位每一個(gè)需要執(zhí)行的任務(wù)打上了觸發(fā)更新時(shí)間標(biāo)簽,那么任務(wù)的優(yōu)先級(jí)還需要進(jìn)一步的確立,requestUpdateLane就是用來(lái)獲取每一個(gè)任務(wù)執(zhí)行的優(yōu)先級(jí)的。

//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.

//獲取執(zhí)行任務(wù)的優(yōu)先級(jí),便于調(diào)度

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

//通過(guò)findUpdateLane函數(shù)重新計(jì)算lane

lane=findUpdateLane(InputDiscreteLanePriority,currentEventWipLanes);

}else{

//根據(jù)優(yōu)先級(jí)計(jì)算法則計(jì)算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,

//根據(jù)計(jì)算得到的schedulerLanePriority,計(jì)算更新的優(yōu)先級(jí)lane

lane=findUpdateLane(schedulerLanePriority,currentEventWipLanes);

returnlane;

}

通過(guò)getCurrentPriorityLevel獲得所有執(zhí)行任務(wù)的調(diào)度優(yōu)先級(jí)schedulerPriority。通過(guò)findUpdateLane計(jì)算lane,作為更新中的優(yōu)先級(jí)。

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,

}

相關(guān)參考視頻講解:進(jìn)入學(xué)習(xí)

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';

//同步任務(wù)

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,//更新時(shí)間

lane,//優(yōu)先級(jí)

tag:UpdateState,//更新

payload:null,//需要更新的內(nèi)容

callback:null,//更新完后的回調(diào)

next:null,//指向下一個(gè)更新

returnupdate;

}

createUpdate函數(shù)入?yún)閑ventTime和lane,輸出一個(gè)update對(duì)象,而對(duì)象中的tag表示此對(duì)象要進(jìn)行什么樣的操作。

exportconstUpdateState=0;//更新

exportconstReplaceState=1;//替換

exportconstForceUpdate=2;//強(qiáng)制更新

exportconstCaptureUpdate=3;//xx更新

createUpdate就是單純的給每一個(gè)任務(wù)進(jìn)行包裝,作為一個(gè)個(gè)體推入到更新隊(duì)列中。

enqueueUpdate

exportfunctionenqueueUpdateState(fiber:Fiber,update:UpdateState){

//獲取當(dāng)前更新隊(duì)列?為啥呢?因?yàn)闊o(wú)法保證react是不是還有正在更新或者沒有更新完畢的任務(wù)

constupdateQueue=fiber.updateQueue;

//如果更新隊(duì)列為空,則表示fiber還未渲染,直接退出

if(updateQueue===null){

//Onlyoccursifthefiberhasbeenunmounted.

return;

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

constpending=sharedQueue.pending;

if(pending===null){

//Thisisthefirstupdate.Createacircularlist.

//還記得那個(gè)更新對(duì)象嗎?update.next=

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

update.next=update;

}else{

//將update插入到更新隊(duì)列循環(huán)當(dāng)中

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;

}

這一步就是把需要更新的對(duì)象,與fiber更新隊(duì)列關(guān)聯(lián)起來(lái)。

總結(jié)

React通過(guò)獲取事件的優(yōu)先級(jí),處理具有同樣優(yōu)先級(jí)的事件,創(chuàng)建更新對(duì)象并與fiber的更新隊(duì)列關(guān)聯(lián)起來(lái)。到這一步updateContainer這個(gè)流程就走完了,也下面就是開始他的協(xié)調(diào)階段了。

協(xié)調(diào)與調(diào)度

協(xié)調(diào)與調(diào)度的流程大致如圖所示:

reconciler流程

React的reconciler流程以scheduleUpdateOnFiber為入口,并在checkForNestedUpdates里面處理任務(wù)更新的嵌套層數(shù),如果嵌套層數(shù)過(guò)大(50),就會(huì)認(rèn)為是無(wú)效更新,則會(huì)拋出異常。之后便根據(jù)markUpdateLaneFromFiberToRoot對(duì)當(dāng)前的fiber樹,自底向上的遞歸fiber的lane,根據(jù)lane做二進(jìn)制比較或者位運(yùn)算處理。詳情如下:

如果當(dāng)前執(zhí)行任務(wù)的優(yōu)先級(jí)為同步,則去判斷有無(wú)正在執(zhí)行的React任務(wù)。如果沒有則執(zhí)行ensureRootIsScheduled,進(jìn)行調(diào)度處理。如果當(dāng)前任務(wù)優(yōu)先級(jí)是異步執(zhí)行,則執(zhí)行ensureRootIsScheduled進(jìn)行調(diào)度處理。

exportfunctionscheduleUpdateOnFiber(

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

//檢查嵌套層數(shù),避免是循環(huán)做無(wú)效操作

checkForNestedUpdates();

warnAboutRenderPhaseUpdatesInDEV(fiber);

//更新當(dāng)前更新隊(duì)列里面的任務(wù)優(yōu)先級(jí),自底而上更新child.fiberLanes

constroot=markUpdateLaneFromFiberToRoot(fiber,lane);

if(root===null){

warnAboutUpdateOnUnmountedFiberInDEV(fiber);

returnnull;

//Markthattheroothasapendingupdate.

//標(biāo)記root有更新的,執(zhí)行它

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.

//獲取當(dāng)前優(yōu)先級(jí)層次

constpriorityLevel=getCurrentPriorityLevel();

//同步任務(wù),采用同步更新的方式

if(lane===SyncLane){

if(

//Checkifwe'reinsideunbatchedUpdates

(executionContextLegacyUnbatchedContext)!==NoContext

//Checkifwe'renotalreadyrendering

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

//Registerpendinginteractionsontheroottoavoidlosingtracedinteractiondata.

//同步而且沒有react任務(wù)在執(zhí)行,調(diào)用performSyncWorkOnRoot

schedulePendingInteractions(root,lane);

//Thisisalegacyedgecase.TheinitialmountofaReactDOM.render-ed

//rootinsideofbatchedUpdatesshouldbesynchronous,butlayoutupdates

//shouldbedeferreduntiltheendofthebatch.

performSyncWorkOnRoot(root);

}else{

//如果有正在執(zhí)行的react任務(wù),那么執(zhí)行它ensureRootIsScheduled去復(fù)用當(dāng)前正在執(zhí)行的任務(wù)

//跟本次更新一起進(jìn)行

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.

//如果此次是異步任務(wù)

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.

//可以中斷更新,只要調(diào)用ensureRootIsScheduled=performConcurrentWorkOnRoot

ensureRootIsScheduled(root,eventTime);

schedulePendingInteractions(root,lane);

//Weusethiswhenassigningalaneforatransitioninside

//`requestUpdateLane`.Weassumeit'sthesameastherootbeingupdated,

//sinceinthecommoncaseofasinglerootappitprobablyis.Ifit'snot

//thesameroot,thenit'snotahugedeal,wejustmightbatchmorestuff

//togethermorethannecessary.

mostRecentlyUpdatedRoot=root;

}

同步任務(wù)類型執(zhí)行機(jī)制

當(dāng)任務(wù)的類型為同步任務(wù),并且當(dāng)前的js主線程空閑,會(huì)通過(guò)performSyncWorkOnRoot(root)方法開始執(zhí)行同步任務(wù)。

performSyncWorkOnRoot里面主要做了兩件事:

renderRootSync從根節(jié)點(diǎn)開始進(jìn)行同步渲染任務(wù)commitRoot執(zhí)行commit流程

當(dāng)前js線程中有正在執(zhí)行的任務(wù)時(shí)候,就會(huì)觸發(fā)ensureRootIsScheduled函數(shù)。ensureRootIsScheduled里面主要是處理當(dāng)前加入的更新任務(wù)的lane是否有變化:

如果沒有變化則表示跟當(dāng)前的schedule一起執(zhí)行。如果有則創(chuàng)建新的schedule。調(diào)用performSyncWorkOnRoot執(zhí)行同步任務(wù)。

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

//同步任務(wù)調(diào)用performSyncWorkOnRoot

newCallbackNode=scheduleSyncCallback(

performSyncWorkOnRoot.bind(null,root),

}elseif(newCallbackPriority===SyncBatchedLanePriority){

newCallbackNode=scheduleCallback(

ImmediateSchedulerPriority,

performSyncWorkOnRoot.bind(null,root),

}else{

//異步任務(wù)調(diào)用performConcurrentWorkOnRoot

constschedulerPriorityLevel=lanePriorityToSchedulerPriority(

newCallbackPriority,

newCallbackNode=scheduleCallback(

schedulerPriorityLevel,

performConcurrentWorkOnRoot.bind(null,root),

root.callbackPriority=newCallbackPriority;

root.callbackNode=newCallbackNode;

}

所以任務(wù)類型為同步的時(shí)候,不管js線程空閑與否,都會(huì)走到performSyncWorkOnRoot,進(jìn)而走renderRootSync、workLoopSync流程,而在workLoopSync中,只要workInProgressfiber不為null,則會(huì)一直循環(huán)執(zhí)行performUnitOfWork,而performUnitOfWork中會(huì)去執(zhí)行beginWork和completeWork,也就是上一章里面說(shuō)的beginWork流程去創(chuàng)建每一個(gè)fiber節(jié)點(diǎn)

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

functionworkLoopSync(){

while(workInProgress!==null){

performUnitOfWork(workInProgress);

}

異步任務(wù)類型執(zhí)行機(jī)制

異步任務(wù)則會(huì)去執(zhí)行performConcurrentWorkOnRoot,進(jìn)而去執(zhí)行renderRootConcurrent、workLoopConcurrent,但是與同步任務(wù)不同的是異步任務(wù)是可以中斷的,這個(gè)可中斷的關(guān)鍵字就在于shouldYield,它本身返回值是一個(gè)false,為true則可以中斷。

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

functionworkLoopConcurrent(){

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

performUnitOfWork(workInProgress);

}

每一次在執(zhí)行performUnitOfWork之前都會(huì)關(guān)注一下shouldYield()返回值,也就是說(shuō)的reconciler過(guò)程可中斷的意思。

shouldYield

//packages\scheduler\src\SchedulerPostTask.js

exportfunctionunstable_shouldYield(){

returngetCurrentTime()=deadline;

}

getCurrentTime為newDate(),deadline為瀏覽器處理每一幀結(jié)束時(shí)間戳,所以這里表示的是,在瀏覽器每一幀空閑的時(shí)候,才會(huì)去處理此任務(wù),如果當(dāng)前任務(wù)在瀏覽器執(zhí)行的某一幀里面,則會(huì)中斷當(dāng)前任務(wù),等待瀏覽器當(dāng)前幀執(zhí)行完畢,等到下一幀空閑的時(shí)候,才會(huì)去執(zhí)行當(dāng)前任務(wù)。

所以不管在workLoopConcurrent還是workLoopSync中,都會(huì)根據(jù)當(dāng)前的workInProgressfiber是否為null來(lái)進(jìn)行循環(huán)調(diào)用performUnitOfWork。根據(jù)流程圖以及上面說(shuō)的這一些,可以看得出來(lái)從beginWork到completeUnitOfWork這個(gè)過(guò)程究竟干了什么。

這三章將會(huì)講解fiber樹的reconcileChildren過(guò)程、completeWork過(guò)程、commitMutationEffectsinsertOrAppendPlacementNodeIntoContainer(DOM)過(guò)程。這里將詳細(xì)解讀v17版本的React的diff算法、虛擬dom到真實(shí)dom的創(chuàng)建,函數(shù)生命鉤子的執(zhí)行流程等。

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里面,每一次執(zhí)行beginWork,進(jìn)行workIngProgress更新,當(dāng)遍歷完畢整棵fiber樹之后便會(huì)執(zhí)行completeUnitOfWork。

beginWork

我們可以看到beginWork就是originBeginWork得實(shí)際執(zhí)行。我們翻開beginWork的源碼可以看到,它便是根據(jù)不同的workInProgress.tag執(zhí)行不同組件類型的處理函數(shù),這里就不去拆分的太細(xì),只有有想法便會(huì)單獨(dú)出一篇文章講述這個(gè)的細(xì)節(jié),但是最后都會(huì)去調(diào)用reconcileChildren。

completeUnitOfWork

當(dāng)遍歷完畢執(zhí)行beginWork,遍歷完畢之后就會(huì)走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.

//把已收集到的副作用,合并到父級(jí)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.

//跳過(guò)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樹上已經(jīng)被打上的副作用標(biāo)簽flags,一直收集到root上面以便于在commit階段進(jìn)行dom的增刪改。

scheduler流程

在這里應(yīng)該有很多人不明白,協(xié)調(diào)和調(diào)度是什么意思,通俗來(lái)講:

協(xié)調(diào)就是協(xié)同合作調(diào)度就是執(zhí)行命令

所以在React中協(xié)調(diào)就是一個(gè)js線程中,需要安排很多模塊去完成整個(gè)流程,例如:同步異步lane的處理,reconcileChildren處理fiber節(jié)點(diǎn)等,保證整個(gè)流程有條不紊的執(zhí)行。調(diào)度表現(xiàn)為讓空閑的js線程(幀層面)去執(zhí)行其他任務(wù),這個(gè)過(guò)程稱之為調(diào)度,那么它到底是怎么去做的呢?

我們回到處理異步任務(wù)那里,我們會(huì)發(fā)現(xiàn)performConcurrentWorkOnRoot這個(gè)函數(shù)外面包裹了一層scheduleCallback:

newCallbackNode=scheduleCallback(

schedulerPriorityLevel,

performConcurrentWorkOnRoot.bind(null,root),

)

exportfunctionscheduleCallback(

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

constpriorityLevel=reactPriorityToSchedulerPriority(reactPriorityLevel);

returnScheduler

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論