在 React 源碼中,scheduleUpdateOnFiber 是所有任務(wù)的唯一入口方法。我們前面分析 useState 的實(shí)現(xiàn)原理章節(jié)中,我們可以清晰的知道,當(dāng)我們調(diào)用 dispatchSetState 時(shí),最終會(huì)調(diào)用該入口方法。
scheduleUpdateOnFiber 主要用于觸發(fā)一個(gè) Fiber 節(jié)點(diǎn)上的調(diào)度更新任務(wù),該函數(shù)里主要有兩個(gè)核心邏輯。
// Mark that the root has a pending update.// 標(biāo)記 root 上有一個(gè)更新任務(wù)markRootUpdated(root, lane, eventTime);ensureRootIsScheduled(root, eventTime);
markRootUpdated 的邏輯如下,簡(jiǎn)單了解一下即可。
export function markRootUpdated( root: FiberRoot, updateLane: Lane, eventTime: number,) { // 設(shè)置本次更新的優(yōu)先級(jí) root.pendingLanes |= updateLane; // 重置 root 應(yīng)用根節(jié)點(diǎn)的優(yōu)先級(jí) if (updateLane !== IdleLane) { // 由 Suspence 而掛起的 update 對(duì)應(yīng)的 lane 集合 root.suspendedLanes = NoLanes; // 由請(qǐng)求成功,Suspence 取消掛起的 update 對(duì)應(yīng)的 Lane 集合 root.pingedLanes = NoLanes; } const eventTimes = root.eventTimes; const index = laneToIndex(updateLane); eventTimes[index] = eventTime;}
ensureRootIsScheduled 的主要目的要確保 root 根節(jié)點(diǎn)被調(diào)度。在該邏輯中,會(huì)根據(jù) root.pendingLanes 信息計(jì)算出本次更新的 Lanes: nextLanes。
const nextLanes = getNextLanes( root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,);
然后根據(jù) nextLanes 計(jì)算出本批次集合中優(yōu)先級(jí)最高的 Lane,作為本地任務(wù)的優(yōu)先級(jí)。
// We use the highest priority lane to represent the priority of the callback.const newCallbackPriority = getHighestPriorityLane(nextLanes);
后續(xù)的邏輯就是取出當(dāng)前已存在的調(diào)度優(yōu)先級(jí),與 newCallbackPriority 進(jìn)行對(duì)比,根據(jù)對(duì)比結(jié)果來執(zhí)行不同的更新方法。當(dāng)該值等于 SyncLane 時(shí),表示為同步更新。
同步優(yōu)先級(jí)例如點(diǎn)擊事件。
然后會(huì)判斷是否支持微任務(wù)更新,如果不支持最后會(huì)執(zhí)行 scheduleCallback。
if (newCallbackPriority === SyncLane) { if (supportsMicrotasks) { // Flush the queue in a microtask. if (__DEV__ && ReactCurrentActQueue.current !== null) { // Inside `act`, use our internal `act` queue so that these get flushed // at the end of the current scope even when using the sync version // of `act`. ReactCurrentActQueue.current.push(flushSyncCallbacks); } else { scheduleMicrotask(() => { // In Safari, appending an iframe forces microtasks to run. // https://github.com/facebook/react/issues/22459 // We don't support running callbacks in the middle of render // or commit so we need to check against that. if ( (executionContext & (RenderContext | CommitContext)) === NoContext ) { // Note that this would still prematurely flush the callbacks // if this happens outside render or commit phase (e.g. in an event). flushSyncCallbacks(); } }); } } else { // Flush the queue in an Immediate task. scheduleCallback(ImmediateSchedulerPriority, flushSyncCallbacks); }}
scheduleSyncCallback 的邏輯,也就是同步任務(wù)的調(diào)度非常簡(jiǎn)單,就是將執(zhí)行同步任務(wù)的回調(diào)添加到一個(gè)同步隊(duì)列 syncQueue 中。
export function scheduleSyncCallback(callback: SchedulerCallback) { // Push this callback into an internal queue. We'll flush these either in // the next tick, or earlier if something calls `flushSyncCallbackQueue`. if (syncQueue === null) { syncQueue = [callback]; } else { // Push onto existing queue. Don't need to schedule a callback because // we already scheduled one when we created the queue. syncQueue.push(callback); }}
這里的 callback 是之前傳入的 performSyncWorkOnRoot,這是用來執(zhí)行同步更新任務(wù)的方法。他的邏輯主要包括:
function performSyncWorkOnRoot(root) { ... let exitStatus = renderRootSync(root, lanes); ... root.finishedWork = finishedWork; root.finishedLanes = lanes; commitRoot( root, workInProgressRootRecoverableErrors, workInProgressTransitions, ); ensureRootIsScheduled(root, now()); return null;}
workLoopSync 的邏輯也非常簡(jiǎn)單,如下:
function workLoopSync() { // Already timed out, so perform work without checking if we need to yield. while (workInProgress !== null) { performUnitOfWork(workInProgress); }}
在 performUnitOfWork 中,會(huì)調(diào)用 beginWork 方法開始創(chuàng)建 Fiber 節(jié)點(diǎn)。
var next = beginWork( current, unitOfWork, subtreeRenderLanes);
同步更新的過程比較簡(jiǎn)單,從 scheduleUpdateOnFiber 到 beginWork 這中間的流程里,大多數(shù)邏輯都在進(jìn)行各種不同情況的判斷,因此源碼看上去比較吃力,實(shí)際邏輯并不是很重要,簡(jiǎn)單了解即可,重要的是 beginWork 創(chuàng)建 Fiber 節(jié)點(diǎn)的方法,這跟我們之前文章里提到過的優(yōu)化策略是一致的。
本文鏈接:http://www.tebozhan.com/showinfo-26-87990-0.html一圖看懂 React 源碼中的同步更新邏輯
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com