functionperformUnitOfWork(workInProgress) { let next = beginWork(workInProgress); if (next === null) { next = completeUnitOfWork(workInProgress); } return next; }
functionbeginWork(workInProgress) { log('work performed for ' + workInProgress.name); return workInProgress.child; }
functioncompleteUnitOfWork(workInProgress) { while (true) { let returnFiber = workInProgress.return; let siblingFiber = workInProgress.sibling;
nextUnitOfWork = completeWork(workInProgress);
if (siblingFiber !== null) { // If there is a sibling, return it // to perform work for this sibling return siblingFiber; } elseif (returnFiber !== null) { // If there's no more work in this returnFiber, // continue the loop to complete the returnFiber. workInProgress = returnFiber; continue; } else { // We've reached the root. returnnull; } } }
functioncompleteWork(workInProgress) { log('work completed for ' + workInProgress.name); returnnull; }
// TODO: Get rid of Sync and use current time? // 这里是同步异步处理分支 这里暂时看同步逻辑 if (expirationTime === Sync) { performSyncWork(); } else { scheduleCallbackWithExpirationTime(root, expirationTime); } }
performSyncWork -> performWork(Sync, false); functionperformWork(minExpirationTime: ExpirationTime, isYieldy: boolean) { // Keep working on roots until there's no more work, or until there's a higher // priority event. findHighestPriorityRoot();
// 这些值可能在后面迭代中被更改。注意是let不是const let newBaseState = queue.baseState; let newFirstUpdate = null; let newExpirationTime = NoWork;
// Iterate through the list of updates to compute the result. let update = queue.firstUpdate; let resultState = newBaseState; while (update !== null) { const updateExpirationTime = update.expirationTime; if (updateExpirationTime < renderExpirationTime) { // 这里分支暂时可以忽略 // 此更新没有足够的优先级。跳过它。 if (newFirstUpdate === null) { // 这是第一次跳过的更新.下次更新列表中它将排第一个 newFirstUpdate = update; // 由于这是第一次跳过的更新, 当前结果是'the new base state'. newBaseState = resultState; } // 由于此更新将保留在列表中,因此请更新剩余的到期时间。 if (newExpirationTime < updateExpirationTime) { newExpirationTime = updateExpirationTime; } } else { // 此更新确实具有足够的优先级。处理它并计算新结果。 // 这个分支做了一下这些事: // 1.根据update.tag等参数,得到目标update.payload的处理后的State值 // 2.根据update.callback设置queue的firstEffect、lastEffect属性 // 以及queue.lastEffect.nextEffect属性 // 3.对queue.next执行上面操作 如此重复 // getStateFromUpdate还是值得看看. update.tag有4个Enum值: // ReplaceState|CaptureUpdate|UpdateState|ForceUpdate // 这里初始render对应的是UpdateState 这里针对Function Component和partialState有特殊处理 // 好吧 这里不管那么多分支 常规的ClassComponent返回的就是一个: // update.payload。 // 简单点理解: (queue.firstUpdate.tag) => { ...queue.firstUpdate.payload } resultState = getStateFromUpdate( workInProgress, queue, update, resultState, props, instance, ); const callback = update.callback; if (callback !== null) { workInProgress.effectTag |= Callback; // Set this to null, in case it was mutated during an aborted render. update.nextEffect = null; if (queue.lastEffect === null) { // 如果这个值为null这queue链表是空 queue.firstEffect = queue.lastEffect = update; } else { // 否则将原来的lastEffect的下个Effect设为update // 然后将lastEffect指向update;这个操作实质上类似链表版本的Array.push // 是将update放到queue链表最后一个位置上 queue.lastEffect.nextEffect = update; queue.lastEffect = update; } } } // Continue to the next update. update = update.next; }
// 迭代list模拟事件捕获 这里不管它只看正常开发用到的冒泡 // 代码略
// 如果有跳过的update 这里会进入分支处理queue.lastUpdate值 if (newFirstUpdate === null) { queue.lastUpdate = null; } if (newFirstCapturedUpdate === null) { queue.lastCapturedUpdate = null; } else { workInProgress.effectTag |= Callback; } if (newFirstUpdate === null && newFirstCapturedUpdate === null) { // We processed every update, without skipping. That means the new base // state is the same as the result state. // 我们处理了每次更新,没有跳过。这意味着新的基本状态与结果状态相同。 newBaseState = resultState; }
// Set the remaining expiration time to be whatever is remaining in the queue. // This should be fine because the only two other things that contribute to // expiration time are props and context. We're already in the middle of the // begin phase by the time we start processing the queue, so we've already // dealt with the props. Context in components that specify // shouldComponentUpdate is tricky; but we'll have to account for // that regardless. workInProgress.expirationTime = newExpirationTime; workInProgress.memoizedState = resultState;
exportfunctionreconcileChildren( current: Fiber | null, workInProgress: Fiber, nextChildren: any, renderExpirationTime: ExpirationTime, ) { if (current === null) { // If this is a fresh new component that hasn't been rendered yet, we // won't update its child set by applying minimal side-effects. Instead, // we will add them all to the child before it gets rendered. That means // we can optimize this reconciliation pass by not tracking side-effects. // 如果是一个新鲜的没有渲染过的组件 我们不会通过最小side-effects更新它的child // 相反 我们会在渲染之前将它们全部添加到子节点 // 这意味着不需要对side-effects进行跟踪 以优化这个reconciliation过程 workInProgress.child = mountChildFibers( // -> ChildReconciler(false) workInProgress, null, nextChildren, renderExpirationTime, ); } else { workInProgress.child = reconcileChildFibers( // -> ChildReconciler(true) workInProgress, current.child, <-- 更新回传入child 以跟踪side-effects nextChildren, renderExpirationTime, ); } }