网站建设做哪 个会计科目17做网站联系

当前位置: 首页 > news >正文

网站建设做哪 个会计科目,17做网站联系,怎样建立自己网站视频,用PYTHON3 做网站requestEventTime 其实在React执行过程中#xff0c;会有数不清的任务要去执行#xff0c;但是他们会有一个优先级的判定#xff0c;假如两个事件的优先级一样#xff0c;那么React是怎么去判定他们两谁先执行呢#xff1f; // packages/react-reconciler/src/ReactFibe…requestEventTime 其实在React执行过程中会有数不清的任务要去执行但是他们会有一个优先级的判定假如两个事件的优先级一样那么React是怎么去判定他们两谁先执行呢 // packages/react-reconciler/src/ReactFiberWorkLoop.old.js export function requestEventTime() {if ((executionContext (RenderContext | CommitContext)) ! NoContext) {// Were inside React, so its fine to read the actual time.// react事件正在执行// executionContext// RenderContext 正在计算// CommitContext 正在提交// export const NoContext /* / 0b0000000;// const BatchedContext / / 0b0000001;// const EventContext / / 0b0000010;// const DiscreteEventContext / / 0b0000100;// const LegacyUnbatchedContext / / 0b0001000;// const RenderContext / / 0b0010000;// const CommitContext / / 0b0100000;// export const RetryAfterError / / 0b1000000;return now();}// 没有在react事件执行 NoTimestamp -1if (currentEventTime ! NoTimestamp) { // 浏览器事件正在执行返回上次的 currentEventTimereturn currentEventTime;}// 重新计算currentEventTime当执行被中断后currentEventTime now();return currentEventTime; }RenderContext与CommitContext表示正在计算更新和正在提交更新返回now()。如果是浏览器事件正在执行中返回上一次的currentEventTime。如果终止或者中断react任务执行的时候则重新获取执行时间now()。获取的时间越小则执行的优先级越高。 now()并不是单纯的new Date()而是判定两次更新任务的时间是否小于10ms来决定是否复用上一次的更新时间Scheduler_now的。 export const now initialTimeMs 10000 ? Scheduler_now : () Scheduler_now() - initialTimeMs;其实各位猜想一下对于10ms级别的任务间隙时间几乎是可以忽略不计的那么这里就可以视为同样的任务不需要有很大的性能开销有利于批量更新。 requestUpdateLane requestEventTime位每一个需要执行的任务打上了触发更新时间标签那么任务的优先级还需要进一步的确立requestUpdateLane就是用来获取每一个任务执行的优先级的。 // packages/react-reconciler/src/ReactFiberWorkLoop.old.js export function requestUpdateLane(fiber: Fiber): Lane {// Special casesconst mode fiber.mode;if ((mode BlockingMode) NoMode) {return (SyncLane: Lane);} else if ((mode ConcurrentMode) NoMode) {return getCurrentPriorityLevel() ImmediateSchedulerPriority? (SyncLane: Lane): (SyncBatchedLane: Lane);} else if (!deferRenderPhaseUpdateToNextBatch (executionContext RenderContext) ! NoContext workInProgressRootRenderLanes ! NoLanes) {// This is a render phase update. These are not officially supported. The// old behavior is to give this the same thread (expiration time) as// whatever is currently rendering. So if you call setState on a component// that happens later in the same render, it will flush. Ideally, we want to// remove the special case and treat them as if they came from an// interleaved event. Regardless, this pattern is not officially supported.// This behavior is only a fallback. The flag only exists until we can roll// out the setState warning, since existing code might accidentally rely on// the current behavior.return pickArbitraryLane(workInProgressRootRenderLanes);}// The algorithm for assigning an update to a lane should be stable for all// updates at the same priority within the same event. To do this, the inputs// to the algorithm must be the same. For example, we use the renderLanes// to avoid choosing a lane that is already in the middle of rendering.//// However, the included lanes could be mutated in between updates in the// same event, like if you perform an update inside flushSync. Or any other// code path that might call prepareFreshStack.//// The trick we use is to cache the first of each of these inputs within an// event. Then reset the cached values once we can be sure the event is over.// Our heuristic for that is whenever we enter a concurrent work loop.//// Well do the same for currentEventPendingLanes below.if (currentEventWipLanes NoLanes) {currentEventWipLanes workInProgressRootIncludedLanes;}const isTransition requestCurrentTransition() ! NoTransition;if (isTransition) {if (currentEventPendingLanes ! NoLanes) {currentEventPendingLanes mostRecentlyUpdatedRoot ! null? mostRecentlyUpdatedRoot.pendingLanes: NoLanes;}return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);}// TODO: Remove this dependency on the Scheduler priority.// To do that, were replacing it with an update lane priority.// 获取执行任务的优先级便于调度const schedulerPriority getCurrentPriorityLevel();// The old behavior was using the priority level of the Scheduler.// This couples React to the Scheduler internals, so were replacing it// with the currentUpdateLanePriority above. As an example of how this// could be problematic, if were not inside Scheduler.runWithPriority,// then well get the priority of the current running Scheduler task,// which is probably not what we want.let lane;if (// TODO: Temporary. Were removing the concept of discrete updates.(executionContext DiscreteEventContext) ! NoContext // 用户block的类型事件schedulerPriority UserBlockingSchedulerPriority) {// 通过findUpdateLane函数重新计算lanelane findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);} else {// 根据优先级计算法则计算laneconst schedulerLanePriority schedulerPriorityToLanePriority(schedulerPriority,);if (decoupleUpdatePriorityFromScheduler) {// In the new strategy, we will track the current update lane priority// inside React and use that priority to select a lane for this update.// For now, were just logging when theyre different so we can assess.const currentUpdateLanePriority getCurrentUpdateLanePriority();if (schedulerLanePriority ! currentUpdateLanePriority currentUpdateLanePriority ! NoLanePriority) {if (DEV) {console.error(Expected current scheduler lane priority %s to match current update lane priority %s,schedulerLanePriority,currentUpdateLanePriority,);}}}// 根据计算得到的 schedulerLanePriority计算更新的优先级 lanelane findUpdateLane(schedulerLanePriority, currentEventWipLanes);}return lane; }通过getCurrentPriorityLevel获得所有执行任务的调度优先级schedulerPriority。通过findUpdateLane计算lane作为更新中的优先级。 findUpdateLane export function findUpdateLane(lanePriority: LanePriority, wipLanes: Lanes, ): Lane {switch (lanePriority) {case NoLanePriority:break;case SyncLanePriority:return SyncLane;case SyncBatchedLanePriority:return SyncBatchedLane;case InputDiscreteLanePriority: {const lane pickArbitraryLane(InputDiscreteLanes ~wipLanes);if (lane NoLane) {// Shift to the next priority levelreturn findUpdateLane(InputContinuousLanePriority, wipLanes);}return lane;}case InputContinuousLanePriority: {const lane pickArbitraryLane(InputContinuousLanes ~wipLanes);if (lane NoLane) {// Shift to the next priority levelreturn findUpdateLane(DefaultLanePriority, wipLanes);}return lane;}case DefaultLanePriority: {let lane pickArbitraryLane(DefaultLanes ~wipLanes);if (lane NoLane) {// If all the default lanes are already being worked on, look for a// lane in the transition range.lane pickArbitraryLane(TransitionLanes ~wipLanes);if (lane NoLane) {// All the transition lanes are taken, too. This should be very// rare, but as a last resort, pick a default lane. This will have// the effect of interrupting the current work-in-progress render.lane pickArbitraryLane(DefaultLanes);}}return lane;}case TransitionPriority: // Should be handled by findTransitionLane insteadcase RetryLanePriority: // Should be handled by findRetryLane insteadbreak;case IdleLanePriority:let lane pickArbitraryLane(IdleLanes ~wipLanes);if (lane NoLane) {lane pickArbitraryLane(IdleLanes);}return lane;default:// The remaining priorities are not valid for updatesbreak;}invariant(false,Invalid update priority: %s. This is a bug in React.,lanePriority,); }相关参考视频讲解进入学习 lanePriority: LanePriority export opaque type LanePriority | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 16| 17; export opaque type Lanes number; export opaque type Lane number; export opaque type LaneMapT ArrayT;import {ImmediatePriority as ImmediateSchedulerPriority,UserBlockingPriority as UserBlockingSchedulerPriority,NormalPriority as NormalSchedulerPriority,LowPriority as LowSchedulerPriority,IdlePriority as IdleSchedulerPriority,NoPriority as NoSchedulerPriority, } from ./SchedulerWithReactIntegration.new;// 同步任务 export const SyncLanePriority: LanePriority 15; export const SyncBatchedLanePriority: LanePriority 14;// 用户事件 const InputDiscreteHydrationLanePriority: LanePriority 13; export const InputDiscreteLanePriority: LanePriority 12;const InputContinuousHydrationLanePriority: LanePriority 11; export const InputContinuousLanePriority: LanePriority 10;const DefaultHydrationLanePriority: LanePriority 9; export const DefaultLanePriority: LanePriority 8;const TransitionHydrationPriority: LanePriority 7; export const TransitionPriority: LanePriority 6;const RetryLanePriority: LanePriority 5;const SelectiveHydrationLanePriority: LanePriority 4;const IdleHydrationLanePriority: LanePriority 3; const IdleLanePriority: LanePriority 2;const OffscreenLanePriority: LanePriority 1;export const NoLanePriority: LanePriority 0;createUpdate export function createUpdate(eventTime: number, lane: Lane): Update {const update: Update* {eventTime, // 更新时间lane, // 优先级tag: UpdateState,//更新payload: null,// 需要更新的内容callback: null, // 更新完后的回调next: null, // 指向下一个更新};return update; }createUpdate函数入参为eventTime和lane输出一个update对象而对象中的tag表示此对象要进行什么样的操作。 export const UpdateState 0;// 更新 export const ReplaceState 1;//替换 export const ForceUpdate 2;//强制更新 export const CaptureUpdate 3;//xx更新createUpdate就是单纯的给每一个任务进行包装作为一个个体推入到更新队列中。 enqueueUpdate export function enqueueUpdateState(fiber: Fiber, update: UpdateState) {// 获取当前更新队列为啥呢因为无法保证react是不是还有正在更新或者没有更新完毕的任务const updateQueue fiber.updateQueue;// 如果更新队列为空则表示fiber还未渲染直接退出if (updateQueue null) {// Only occurs if the fiber has been unmounted.return;}const sharedQueue: SharedQueueState (updateQueue: any).shared;const pending sharedQueue.pending;if (pending null) {// This is the first update. Create a circular list.// 还记得那个更新对象吗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(An update (setState, replaceState, or forceUpdate) was scheduled from inside an update function. Update functions should be pure, with zero side-effects. Consider using componentDidUpdate or a callback.,);didWarnUpdateInsideUpdate true;}} }这一步就是把需要更新的对象与fiber更新队列关联起来。 总结 React通过获取事件的优先级处理具有同样优先级的事件创建更新对象并与fiber的更新队列关联起来。到这一步updateContainer这个流程就走完了也下面就是开始他的协调阶段了。 协调与调度 协调与调度的流程大致如图所示 reconciler流程 React的reconciler流程以scheduleUpdateOnFiber为入口并在checkForNestedUpdates里面处理任务更新的嵌套层数如果嵌套层数过大 50 就会认为是无效更新则会抛出异常。之后便根据markUpdateLaneFromFiberToRoot对当前的fiber树自底向上的递归fiber的lane根据lane做二进制比较或者位运算处理。详情如下 如果当前执行任务的优先级为同步则去判断有无正在执行的React任务。如果没有则执行ensureRootIsScheduled进行调度处理。如果当前任务优先级是异步执行则执行ensureRootIsScheduled进行调度处理。 export function scheduleUpdateOnFiber(fiber: Fiber, lane: Lane, eventTime: number, ) {// 检查嵌套层数避免是循环做无效操作checkForNestedUpdates();warnAboutRenderPhaseUpdatesInDEV(fiber);// 更新当前更新队列里面的任务优先级,自底而上更新child.fiberLanesconst root markUpdateLaneFromFiberToRoot(fiber, lane);if (root null) {warnAboutUpdateOnUnmountedFiberInDEV(fiber);return null;}// Mark that the root has a pending update.// 标记root有更新的执行它markRootUpdated(root, lane, eventTime);if (root workInProgressRoot) {// Received an update to a tree thats in the middle of rendering. Mark// that there was an interleaved update work on this root. Unless the// deferRenderPhaseUpdateToNextBatch flag is off and this is a render// phase update. In that case, we dont treat render phase updates as if// they were interleaved, for backwards compat reasons.if (deferRenderPhaseUpdateToNextBatch ||(executionContext RenderContext) NoContext) {workInProgressRootUpdatedLanes mergeLanes(workInProgressRootUpdatedLanes,lane,);}if (workInProgressRootExitStatus RootSuspendedWithDelay) {// The root already suspended with a delay, which means this render// definitely wont finish. Since we have a new update, lets mark it as// suspended now, right before marking the incoming update. This has the// effect of interrupting the current render and switching to the update.// TODO: Make sure this doesnt override pings that happen while weve// already started rendering.markRootSuspended(root, workInProgressRootRenderLanes);}}// TODO: requestUpdateLanePriority also reads the priority. Pass the// priority as an argument to that function and this one.// 获取当前优先级层次const priorityLevel getCurrentPriorityLevel();// 同步任务采用同步更新的方式if (lane SyncLane) {if (// Check if were inside unbatchedUpdates(executionContext LegacyUnbatchedContext) ! NoContext // Check if were not already rendering(executionContext (RenderContext | CommitContext)) NoContext) {// Register pending interactions on the root to avoid losing traced interaction data.// 同步而且没有react任务在执行调用performSyncWorkOnRootschedulePendingInteractions(root, lane);// This is a legacy edge case. The initial mount of a ReactDOM.render-ed// root inside of batchedUpdates should be synchronous, but layout updates// should be deferred until the end of the batch.performSyncWorkOnRoot(root);} else {// 如果有正在执行的react任务那么执行它ensureRootIsScheduled去复用当前正在执行的任务// 跟本次更新一起进行ensureRootIsScheduled(root, eventTime);schedulePendingInteractions(root, lane);if (executionContext NoContext) {// Flush the synchronous work now, unless were already working or inside// a batch. This is intentionally inside scheduleUpdateOnFiber instead of// scheduleCallbackForFiber to preserve the ability to schedule a callback// without immediately flushing it. We only do this for user-initiated// updates, to preserve historical behavior of legacy mode.resetRenderTimer();flushSyncCallbackQueue();}}} else {// Schedule a discrete update but only if its not Sync.// 如果此次是异步任务if ((executionContext DiscreteEventContext) ! NoContext // Only updates at user-blocking priority or greater are considered// discrete, even inside a discrete event.(priorityLevel UserBlockingSchedulerPriority ||priorityLevel ImmediateSchedulerPriority)) {// This is the result of a discrete event. Track the lowest priority// discrete update per root so we can flush them early, if needed.if (rootsWithPendingDiscreteUpdates null) {rootsWithPendingDiscreteUpdates new Set([root]);} else {rootsWithPendingDiscreteUpdates.add(root);}}// Schedule other updates after in case the callback is sync.// 可以中断更新只要调用ensureRootIsScheduled performConcurrentWorkOnRootensureRootIsScheduled(root, eventTime);schedulePendingInteractions(root, lane);}// We use this when assigning a lane for a transition inside// requestUpdateLane. We assume its the same as the root being updated,// since in the common case of a single root app it probably is. If its not// the same root, then its not a huge deal, we just might batch more stuff// together more than necessary.mostRecentlyUpdatedRoot root; }同步任务类型执行机制 当任务的类型为同步任务并且当前的js主线程空闲会通过 performSyncWorkOnRoot(root) 方法开始执行同步任务。 performSyncWorkOnRoot 里面主要做了两件事 renderRootSync 从根节点开始进行同步渲染任务commitRoot 执行 commit 流程 当前js线程中有正在执行的任务时候就会触发ensureRootIsScheduled函数。 ensureRootIsScheduled里面主要是处理当前加入的更新任务的lane是否有变化 如果没有变化则表示跟当前的schedule一起执行。如果有则创建新的schedule。调用performSyncWorkOnRoot执行同步任务。 function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {const existingCallbackNode root.callbackNode;// Check if any lanes are being starved by other work. If so, mark them as// expired so we know to work on those next.markStarvedLanesAsExpired(root, currentTime);// Determine the next lanes to work on, and their priority.const nextLanes getNextLanes(root,root workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,);// This returns the priority level computed during the getNextLanes call.const newCallbackPriority returnNextLanesPriority();if (nextLanes NoLanes) {// Special case: Theres nothing to work on.if (existingCallbackNode ! null) {cancelCallback(existingCallbackNode);root.callbackNode null;root.callbackPriority NoLanePriority;}return;}// Check if theres an existing task. We may be able to reuse it.if (existingCallbackNode ! null) {const existingCallbackPriority root.callbackPriority;if (existingCallbackPriority newCallbackPriority) {// The priority hasnt changed. We can reuse the existing task. Exit.return;}// The priority changed. Cancel the existing callback. Well schedule a new// one below.cancelCallback(existingCallbackNode);}// Schedule a new callback.let newCallbackNode;if (newCallbackPriority SyncLanePriority) {// Special case: Sync React callbacks are scheduled on a special// internal queue// 同步任务调用performSyncWorkOnRootnewCallbackNode scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root),);} else if (newCallbackPriority SyncBatchedLanePriority) {newCallbackNode scheduleCallback(ImmediateSchedulerPriority,performSyncWorkOnRoot.bind(null, root),);} else {// 异步任务调用 performConcurrentWorkOnRootconst schedulerPriorityLevel lanePriorityToSchedulerPriority(newCallbackPriority,);newCallbackNode scheduleCallback(schedulerPriorityLevel,performConcurrentWorkOnRoot.bind(null, root),);}root.callbackPriority newCallbackPriority;root.callbackNode newCallbackNode; }所以任务类型为同步的时候不管js线程空闲与否都会走到performSyncWorkOnRoot进而走renderRootSync、workLoopSync流程而在workLoopSync中只要workInProgress fiber不为null则会一直循环执行performUnitOfWork而performUnitOfWork中会去执行beginWork和completeWork也就是上一章里面说的beginWork流程去创建每一个fiber节点 // packages/react-reconciler/src/ReactFiberWorkLoop.old.jsfunction workLoopSync() {while (workInProgress ! null) {performUnitOfWork(workInProgress);} }异步任务类型执行机制 异步任务则会去执行performConcurrentWorkOnRoot进而去执行renderRootConcurrent、workLoopConcurrent但是与同步任务不同的是异步任务是可以中断的这个可中断的关键字就在于shouldYield它本身返回值是一个false为true则可以中断。 // packages/react-reconciler/src/ReactFiberWorkLoop.old.jsfunction workLoopConcurrent() {while (workInProgress ! null !shouldYield()) {performUnitOfWork(workInProgress);} }每一次在执行performUnitOfWork之前都会关注一下shouldYield()返回值也就是说的reconciler过程可中断的意思。 shouldYield // packages\scheduler\src\SchedulerPostTask.js export function unstable_shouldYield() {return getCurrentTime() deadline; }getCurrentTime为new Date()deadline为浏览器处理每一帧结束时间戳所以这里表示的是在浏览器每一帧空闲的时候才会去处理此任务如果当前任务在浏览器执行的某一帧里面则会中断当前任务等待浏览器当前帧执行完毕等到下一帧空闲的时候才会去执行当前任务。 所以不管在workLoopConcurrent还是workLoopSync中都会根据当前的workInProgress fiber是否为null来进行循环调用performUnitOfWork。根据流程图以及上面说的这一些可以看得出来从beginWork到completeUnitOfWork这个过程究竟干了什么。 这三章将会讲解fiber树的reconcileChildren过程、completeWork过程、commitMutationEffects…insertOrAppendPlacementNodeIntoContainer(DOM)过程。这里将详细解读v17版本的React的diff算法、虚拟dom到真实dom的创建函数生命钩子的执行流程等。 performUnitOfWork function performUnitOfWork(unitOfWork: Fiber): void {// The current, flushed, state of this fiber is the alternate. Ideally// nothing should rely on this, but relying on it here means that we dont// need an additional field on the work in progress.const current unitOfWork.alternate;setCurrentDebugFiberInDEV(unitOfWork);let next;if (enableProfilerTimer (unitOfWork.mode ProfileMode) ! NoMode) {startProfilerTimer(unitOfWork);next beginWork(current, unitOfWork, subtreeRenderLanes);stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);} else {// beginWorknext beginWork(current, unitOfWork, subtreeRenderLanes);}resetCurrentDebugFiberInDEV();unitOfWork.memoizedProps unitOfWork.pendingProps;if (next null) {// If this doesnt spawn new work, complete the current work.// completeUnitOfWorkcompleteUnitOfWork(unitOfWork);} else {workInProgress next;}ReactCurrentOwner.current null; }所以在performUnitOfWork里面每一次执行beginWork进行workIngProgress更新当遍历完毕整棵fiber树之后便会执行completeUnitOfWork。 beginWork 我们可以看到beginWork就是originBeginWork得实际执行。我们翻开beginWork的源码可以看到它便是根据不同的workInProgress.tag执行不同组件类型的处理函数这里就不去拆分的太细只有有想法便会单独出一篇文章讲述这个的细节但是最后都会去调用reconcileChildren。 completeUnitOfWork 当遍历完毕执行beginWork遍历完毕之后就会走completeUnitOfWork。 function completeUnitOfWork(unitOfWork: Fiber): void {// Attempt to complete the current unit of work, then move to the next// sibling. If there are no more siblings, return to the parent fiber.let completedWork unitOfWork;do {// The current, flushed, state of this fiber is the alternate. Ideally// nothing should rely on this, but relying on it here means that we dont// need an additional field on the work in progress.const current completedWork.alternate;const returnFiber completedWork.return;// Check if the work completed or if something threw.if ((completedWork.flags Incomplete) NoFlags) {setCurrentDebugFiberInDEV(completedWork);let next;if (!enableProfilerTimer ||(completedWork.mode ProfileMode) NoMode) {// 绑定事件更新props更新domnext completeWork(current, completedWork, subtreeRenderLanes);} else {startProfilerTimer(completedWork);next completeWork(current, completedWork, subtreeRenderLanes);// Update render duration assuming we didnt error.stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);}resetCurrentDebugFiberInDEV();if (next ! null) {// Completing this fiber spawned new work. Work on that next.workInProgress next;return;}resetChildLanes(completedWork);if (returnFiber ! null // Do not append effects to parents if a sibling failed to complete(returnFiber.flags Incomplete) NoFlags) {// Append all the effects of the subtree and this fiber onto the effect// list of the parent. The completion order of the children affects the// side-effect order.// 把已收集到的副作用合并到父级effect lists中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;}// If this fiber had side-effects, we append it AFTER the childrens// side-effects. We can perform certain side-effects earlier if needed,// by doing multiple passes over the effect list. We dont want to// schedule our own side-effect on our own list because if end up// reusing children well schedule this effect onto itself since were// at the end.const flags completedWork.flags;// Skip both NoWork and PerformedWork tags when creating the effect// list. PerformedWork effect is read by React DevTools but shouldnt be// committed.// 跳过NoWorkPerformedWork在commit阶段用不到if (flags PerformedWork) {if (returnFiber.lastEffect ! null) {returnFiber.lastEffect.nextEffect completedWork;} else {returnFiber.firstEffect completedWork;}returnFiber.lastEffect completedWork;}}} else {// This fiber did not complete because something threw. Pop values off// the stack without entering the complete phase. If this is a boundary,// capture values if possible.const next unwindWork(completedWork, subtreeRenderLanes);// Because this fiber did not complete, dont reset its expiration time.if (next ! null) {// If completing this work spawned new work, do that next. Well come// back here again.// Since were restarting, remove anything that is not a host effect// from the effect tag.next.flags HostEffectMask;workInProgress next;return;}if (enableProfilerTimer (completedWork.mode ProfileMode) ! NoMode) {// Record the render duration for the fiber that errored.stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);// Include the time spent working on failed children before continuing.let actualDuration completedWork.actualDuration;let child completedWork.child;while (child ! null) {actualDuration child.actualDuration;child child.sibling;}completedWork.actualDuration actualDuration;}if (returnFiber ! null) {// Mark the parent fiber as incomplete and clear its effect list.returnFiber.firstEffect returnFiber.lastEffect null;returnFiber.flags | Incomplete;}}// 兄弟层指针const siblingFiber completedWork.sibling;if (siblingFiber ! null) {// If there is more work to do in this returnFiber, do that next.workInProgress siblingFiber;return;}// Otherwise, return to the parentcompletedWork returnFiber;// Update the next thing were working on in case something throws.workInProgress completedWork;} while (completedWork ! null);// Weve reached the root.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), )export function scheduleCallback(reactPriorityLevel: ReactPriorityLevel, callback: SchedulerCallback, options: SchedulerCallbackOptions | void | null, ) {const priorityLevel reactPriorityToSchedulerPriority(reactPriorityLevel);return Scheduler_scheduleCallback(priorityLevel, callback, options); }我们几经周折找到了声明函数的地方 // packages/scheduler/src/Scheduler.js function unstable_scheduleCallback(priorityLevel, callback, options) {var currentTime getCurrentTime();var startTime;if (typeof options object options ! null) {var delay options.delay;if (typeof delay number delay 0) {startTime currentTime delay;} else {startTime currentTime;}} else {startTime currentTime;}var timeout;switch (priorityLevel) {case ImmediatePriority:timeout IMMEDIATE_PRIORITY_TIMEOUT;break;case UserBlockingPriority:timeout USER_BLOCKING_PRIORITY_TIMEOUT;break;case IdlePriority:timeout IDLE_PRIORITY_TIMEOUT;break;case LowPriority:timeout LOW_PRIORITY_TIMEOUT;break;case NormalPriority:default:timeout NORMAL_PRIORITY_TIMEOUT;break;}var expirationTime startTime timeout;var newTask {id: taskIdCounter,callback,priorityLevel,startTime,expirationTime,sortIndex: -1,};if (enableProfiling) {newTask.isQueued false;}if (startTime currentTime) {// This is a delayed task.newTask.sortIndex startTime;push(timerQueue, newTask);if (peek(taskQueue) null newTask peek(timerQueue)) {// All tasks are delayed, and this is the task with the earliest delay.if (isHostTimeoutScheduled) {// Cancel an existing timeout.cancelHostTimeout();} else {isHostTimeoutScheduled true;}// Schedule a timeout.requestHostTimeout(handleTimeout, startTime - currentTime);}} else {newTask.sortIndex expirationTime;push(taskQueue, newTask);if (enableProfiling) {markTaskStart(newTask, currentTime);newTask.isQueued true;}// Schedule a host callback, if needed. If were already performing work,// wait until the next time we yield.if (!isHostCallbackScheduled !isPerformingWork) {isHostCallbackScheduled true;requestHostCallback(flushWork);}}return newTask; }当starttime currentTime的时候表示任务超时插入超时队列。任务没有超时插入调度队列执行requestHostCallback调度任务。 // 创建消息通道const channel new MessageChannel();const port channel.port2;channel.port1.onmessage performWorkUntilDeadline;// 告知scheduler开始调度requestHostCallback function(callback) {scheduledHostCallback callback;if (!isMessageLoopRunning) {isMessageLoopRunning true;port.postMessage(null);}};react通过 new MessageChannel() 创建了消息通道当发现js线程空闲时通过postMessage通知 scheduler开始调度。performWorkUntilDeadline函数功能为处理react调度开始时间更新到结束时间。 这里我们要关注一下设备帧速率。 forceFrameRate function(fps) {if (fps 0 || fps 125) {// Using console[error] to evade Babel and ESLintconsoleerror;return;}if (fps 0) {yieldInterval Math.floor(1000 / fps);} else {// reset the framerateyieldInterval 5;}};performWorkUntilDeadline const performWorkUntilDeadline () {if (scheduledHostCallback ! null) {const currentTime getCurrentTime();// Yield after yieldInterval ms, regardless of where we are in the vsync// cycle. This means theres always time remaining at the beginning of// the message event.// 更新当前帧结束时间deadline currentTime yieldInterval;const hasTimeRemaining true;try {const hasMoreWork scheduledHostCallback(hasTimeRemaining,currentTime,);// 还有任务就继续执行if (!hasMoreWork) {isMessageLoopRunning false;scheduledHostCallback null;} else {// If theres more work, schedule the next message event at the end// of the preceding one.// 没有就postMessageport.postMessage(null);}} catch (error) {// If a scheduler task throws, exit the current browser task so the// error can be observed.port.postMessage(null);throw error;}} else {isMessageLoopRunning false;}// Yielding to the browser will give it a chance to paint, so we can// reset this.needsPaint false;};总结 本文讲了React在状态改变的时候会根据当前任务优先级等一些列操作去创建workInProgress fiber链表树在协调阶段会根据浏览器每一帧去做比较假如浏览器每一帧执行时间戳高于当前时间则表示当前帧没有空闲时间当前任务则必须要等到下一个空闲帧才能去执行的可中断的策略。还有关于beginWork的遍历执行更新fiber的节点。那么到这里这一章就讲述完毕了下一章讲一讲React的diff算法