自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一圖看懂 React 源碼中的同步更新邏輯

開發(fā) 前端
同步更新的過程比較簡單,從 ScheduleUpdateOnFiber 到 BeginWork 這中間的流程里,大多數(shù)邏輯都在進(jìn)行各種不同情況的判斷,因此源碼看上去比較吃力,實(shí)際邏輯并不是很重要,簡單了解即可。

在 React 源碼中,scheduleUpdateOnFiber 是所有任務(wù)的唯一入口方法。我們前面分析 useState 的實(shí)現(xiàn)原理章節(jié)中,我們可以清晰的知道,當(dāng)我們調(diào)用 dispatchSetState 時,最終會調(diào)用該入口方法。

scheduleUpdateOnFiber 主要用于觸發(fā)一個 Fiber 節(jié)點(diǎn)上的調(diào)度更新任務(wù),該函數(shù)里主要有兩個核心邏輯。

// Mark that the root has a pending update.
// 標(biāo)記 root 上有一個更新任務(wù)
markRootUpdated(root, lane, eventTime);

ensureRootIsScheduled(root, eventTime);

markRootUpdated 的邏輯如下,簡單了解一下即可。

export function markRootUpdated(
  root: FiberRoot,
  updateLane: Lane,
  eventTime: number,
) {

  // 設(shè)置本次更新的優(yōu)先級
  root.pendingLanes |= updateLane;

  // 重置 root 應(yīng)用根節(jié)點(diǎn)的優(yōu)先級
  if (updateLane !== IdleLane) {  
    // 由 Suspence 而掛起的 update 對應(yīng)的 lane 集合
    root.suspendedLanes = NoLanes; 
    // 由請求成功,Suspence 取消掛起的 update 對應(yīng)的 Lane 集合
    root.pingedLanes = NoLanes; 
  }

  const eventTimes = root.eventTimes;
  const index = laneToIndex(updateLane);
  eventTimes[index] = eventTime;
}

ensureRootIsScheduled 的主要目的要確保 root 根節(jié)點(diǎn)被調(diào)度。在該邏輯中,會根據(jù) root.pendingLanes 信息計算出本次更新的 Lanes: nextLanes。

const nextLanes = getNextLanes(
  root,
  root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
);

然后根據(jù) nextLanes 計算出本批次集合中優(yōu)先級最高的 Lane,作為本地任務(wù)的優(yōu)先級。

// We use the highest priority lane to represent the priority of the callback.
const newCallbackPriority = getHighestPriorityLane(nextLanes);

后續(xù)的邏輯就是取出當(dāng)前已存在的調(diào)度優(yōu)先級,與 newCallbackPriority 進(jìn)行對比,根據(jù)對比結(jié)果來執(zhí)行不同的更新方法。當(dāng)該值等于 SyncLane 時,表示為同步更新。

同步優(yōu)先級例如點(diǎn)擊事件。

然后會判斷是否支持微任務(wù)更新,如果不支持最后會執(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)度非常簡單,就是將執(zhí)行同步任務(wù)的回調(diào)添加到一個同步隊列 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ù)的方法。他的邏輯主要包括:

  • 調(diào)用 renderRootSync,該方法會執(zhí)行 workLoopSync,最后生成 Fiber true。
  • 將創(chuàng)建完成的 Fiber tree 掛載到 root 節(jié)點(diǎn)上。
  • 最后調(diào)用 commitRoot,進(jìn)入 commit 階段修改真實(shí) DOM。
function performSyncWorkOnRoot(root) {
  ...
  let exitStatus = renderRootSync(root, lanes);
  
  ...
  root.finishedWork = finishedWork;
  root.finishedLanes = lanes;
  commitRoot(
    root,
    workInProgressRootRecoverableErrors,
    workInProgressTransitions,
  );

  ensureRootIsScheduled(root, now());

  return null;
}

workLoopSync 的邏輯也非常簡單,如下:

function workLoopSync() {
  // Already timed out, so perform work without checking if we need to yield.
  while (workInProgress !== null) {
    performUnitOfWork(workInProgress);
  }
}

在 performUnitOfWork 中,會調(diào)用 beginWork 方法開始創(chuàng)建 Fiber 節(jié)點(diǎn)。

var next = beginWork(
  current, 
  unitOfWork, 
  subtreeRenderLanes
);

總結(jié)

同步更新的過程比較簡單,從 scheduleUpdateOnFiber 到 beginWork 這中間的流程里,大多數(shù)邏輯都在進(jìn)行各種不同情況的判斷,因此源碼看上去比較吃力,實(shí)際邏輯并不是很重要,簡單了解即可,重要的是 beginWork 創(chuàng)建 Fiber 節(jié)點(diǎn)的方法,這跟我們之前文章里提到過的優(yōu)化策略是一致的。

責(zé)任編輯:姜華 來源: 這波能反殺
相關(guān)推薦

2017-04-12 11:15:52

ReactsetState策略

2023-11-28 09:44:10

2023-11-01 09:00:14

存儲Docker服務(wù)器

2023-04-07 08:02:54

源碼位邏輯運(yùn)算符

2020-05-20 14:25:45

Reactreact.js前端

2019-06-26 19:18:05

Windows 10系統(tǒng)更新微軟

2021-01-01 09:04:44

Linux內(nèi)核變量

2025-01-20 09:15:00

iOS 18.3蘋果iOS 18

2023-05-17 19:30:52

企業(yè)

2024-02-19 14:58:34

編程范式開發(fā)

2015-03-10 10:15:27

AppleWatch開發(fā)Swift

2024-01-24 09:14:27

編程范式數(shù)據(jù)

2024-02-21 14:06:00

Linux文件系統(tǒng)

2021-10-11 09:41:20

React位運(yùn)算技巧前端

2019-11-24 19:17:06

MySQL異步復(fù)制全同步復(fù)制

2021-04-26 09:22:07

ASP.NET Cor服務(wù)周期

2024-07-16 14:52:31

擴(kuò)展系統(tǒng)負(fù)載均衡器

2019-03-18 15:00:48

SQLJoin用法數(shù)據(jù)庫

2020-10-21 08:38:47

React源碼

2019-08-26 09:12:20

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號