亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

React Fiber源碼分析 第二篇(同步模式)

OBKoro1 / 817人閱讀

摘要:函數(shù)主要執(zhí)行兩個(gè)操作,一個(gè)是判斷當(dāng)前是否還有任務(wù),如果沒有,則從鏈中移除。

系列文章

React Fiber源碼分析 第一篇
React Fiber源碼分析 第二篇(同步模式)
React Fiber源碼分析 第三篇(異步狀態(tài))
React Fiber源碼分析 第四篇(歸納總結(jié))

前言

React Fiber是React在V16版本中的大更新,利用了閑余時(shí)間看了一些源碼,做個(gè)小記錄~
如果有錯(cuò)誤,請(qǐng)輕噴

流程圖 流程圖1

流程圖2

源碼分析

1.scheduleRootUpdate這個(gè)函數(shù)主要執(zhí)行了兩個(gè)操作 1個(gè)是創(chuàng)建更新createUpdate并放到更新隊(duì)列enqueueUpdate, 1個(gè)是執(zhí)行sheculeWork函數(shù)

function scheduleRootUpdate(current$$1, element, expirationTime, callback) {
var update = createUpdate(expirationTime);
  update.payload = { element: element };

  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    update.callback = callback;
  }
  enqueueUpdate(current$$1, update);

  scheduleWork(current$$1, expirationTime);
  return expirationTime;
}

2.先從createUpdate函數(shù)分析, 他直接返回了一個(gè)包含了更新信息的對(duì)象

function createUpdate(expirationTime) {
  return {
    // 優(yōu)先級(jí)
    expirationTime: expirationTime,
    // 更新類型
    tag: UpdateState,
    // 更新的對(duì)象
    payload: null,
    callback: null,
    // 指向下一個(gè)更新
    next: null,
    // 指向下一個(gè)更新effect
    nextEffect: null
  };
}

3.接著更新payload和callback屬性, payload即為更新的對(duì)象, 然后執(zhí)行enqueuUpdateenqueueUpdate相對(duì)比較容易理解, 不過里面有一注釋挺重要

Both queues are non-empty. The last update is the same in both lists, because of structural sharing. So, only append to one of the lists 意思是alternate的updateQueue和fiber的updateQueue是同一個(gè)對(duì)象引用,這里會(huì)在createWorkInProcess提到

往下走就是重要的scheduleWork, 它是render階段真正的開始

function scheduleWork(fiber, expirationTime) {
  // 更新優(yōu)先級(jí)
  var root = scheduleWorkToRoot(fiber, expirationTime);
  ...if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime < nextRenderExpirationTime) {
    // This is an interruption. (Used for performance tracking.) 如果這是一個(gè)打斷原有更新的任務(wù), 先把現(xiàn)有任務(wù)記錄
    interruptedBy = fiber;
    resetStack();
  }
  // 設(shè)置下一個(gè)操作時(shí)間nextExpirationTimeToWorkOn
  markPendingPriorityLevel(root, expirationTime);
  if (
  // If we"re in the render phase, we don"t need to schedule this root
  // for an update, because we"ll do it before we exit...
  !isWorking || isCommitting$1 ||
  // ...unless this is a different root than the one we"re rendering.
  nextRoot !== root) {
    var rootExpirationTime = root.expirationTime;
    requestWork(root, rootExpirationTime);
  }
  ...
}

4.scheduleWork先執(zhí)行一個(gè)scheduleWorkToRoot函數(shù), 該函數(shù)主要是更新其expirationTime以及上層fiberchildrenExpirationTime

function scheduleWorkToRoot(fiber, expirationTime) {
  // Update the source fiber"s expiration time
  if (fiber.expirationTime === NoWork || fiber.expirationTime > expirationTime) {
    fiber.expirationTime = expirationTime;
  }
  var alternate = fiber.alternate;
  if (alternate !== null && (alternate.expirationTime === NoWork || alternate.expirationTime > expirationTime)) {
    alternate.expirationTime = expirationTime;
  }
  // 如果是HostRoot 即直接返回
  var node = fiber.return;
  if (node === null && fiber.tag === HostRoot) {
    return fiber.stateNode;
  }
  // 若子fiber中有更新, 即更新其childrenExpirationTime
  while (node !== null) {
    ...
  }
  return null;
}

5.接著會(huì)執(zhí)行一個(gè)markPendingPriorityLevel函數(shù),這個(gè)函數(shù)主要是更新root的最高優(yōu)先級(jí)和最低優(yōu)先級(jí)(earliestPendingTime和lastestPendingTime;), 同時(shí)設(shè)置下一個(gè)執(zhí)行操作的時(shí)間nextExpirationTimeToWorkOn(即root中具有最高優(yōu)先級(jí)的fiber的expirationTime),關(guān)于這個(gè)函數(shù)的latestSuspendedTime;以后再說

最后scheduleWork會(huì)執(zhí)行requestWork

function requestWork(root, expirationTime) {
  addRootToSchedule(root, expirationTime);
  if (isRendering) {
    // rendering狀態(tài),直接返回
    return;
  }

  if (isBatchingUpdates) {
    // isBatchingUpdates, 直接返回。 react的state更新是會(huì)合并的
    ...return;
  }

  // TODO: Get rid of Sync and use current time?
  if (expirationTime === Sync) {
    // 執(zhí)行同步
    performSyncWork();
  } else {
    // 異步, 暫不分析
    scheduleCallbackWithExpirationTime(root, expirationTime);
  }
}

6.requestWork 會(huì)先執(zhí)行addRootToSchedule,由函數(shù)名稱可知其作用,將root加到schedule, 即設(shè)置firstScheduledRootlastScheduledRoot以及他們的nextScheduleRoot屬性,說白了就是一個(gè)閉環(huán)鏈?zhǔn)浇Y(jié)構(gòu) first => next => next => last(next => first), 同時(shí)更新rootexpirationTime屬性

function addRootToSchedule(root, expirationTime) {
   // root尚未開始過任務(wù) 將root加到schedule
  if (root.nextScheduledRoot === null) {
    ...
  } else {
    // root已經(jīng)開始執(zhí)行過任務(wù), 更新root的expirationTime
    var remainingExpirationTime = root.expirationTime;
    if (remainingExpirationTime === NoWork || expirationTime < remainingExpirationTime) {
      root.expirationTime = expirationTime;
    }
  }
}

7.接著requestWork會(huì)判斷是否正在渲染中,防止重入。剩余的工作將安排在當(dāng)前渲染批次的末尾,如果正在渲染直接返回后, 因?yàn)橐呀?jīng)把root加上到Schedule里面了,依然會(huì)把該root執(zhí)行
同時(shí)判斷是否正在batch update, 這里留到分析setState的時(shí)候說, 最后根據(jù)異步或者同步執(zhí)行不同函數(shù), 此處執(zhí)行同步performSyncWork(),performSyncWork直接執(zhí)行performWork(Sync, null);

function performWork(minExpirationTime, dl) {
  deadline = dl;
  // 找出優(yōu)先級(jí)最高的root
  findHighestPriorityRoot();

  if (deadline !== null) {
    // ...異步
  } else {
    // 循環(huán)執(zhí)行root任務(wù)
    while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || minExpirationTime >= nextFlushedExpirationTime)) {
      performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, true);
      findHighestPriorityRoot();
    }
  }
  ...
  // If there"s work left over, schedule a new callback.
  if (nextFlushedExpirationTime !== NoWork) {
    scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime);
  }
 ...
}

8.performWork首先執(zhí)行findHighestPriorityRoot函數(shù)。findHighestPriorityRoot函數(shù)主要執(zhí)行兩個(gè)操作, 一個(gè)是判斷當(dāng)前root是否還有任務(wù),如果沒有, 則從firstScheuleRoot鏈中移除。 一個(gè)是找出優(yōu)先級(jí)最高的root和其對(duì)應(yīng)的優(yōu)先級(jí)并賦值給
nextFlushedRootnextFlushedExpirationTime

function findHighestPriorityRoot() {
  var highestPriorityWork = NoWork;
  var highestPriorityRoot = null;
  if (lastScheduledRoot !== null) {
    var previousScheduledRoot = lastScheduledRoot;
    var root = firstScheduledRoot;
    while (root !== null) {
      var remainingExpirationTime = root.expirationTime;
      if (remainingExpirationTime === NoWork) {
         // 判斷是否還有任務(wù)并移除
      } else {
         // 找出最高的優(yōu)先級(jí)root和其對(duì)應(yīng)的優(yōu)先級(jí)
      }
    }
  }
  // 賦值
  nextFlushedRoot = highestPriorityRoot;
  nextFlushedExpirationTime = highestPriorityWork;
}

9.緊著, performWork會(huì)根據(jù)傳入的參數(shù)dl來判斷進(jìn)行同步或者異步操作, 這里暫不討論異步,

while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || minExpirationTime >= nextFlushedExpirationTime)) {
      performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, true);
      findHighestPriorityRoot();
    }

10.接著, 會(huì)進(jìn)行performWorkOnRoot函數(shù), 并傳入優(yōu)先級(jí)最高的root和其對(duì)應(yīng)的expirationTime以及一個(gè)true作為參數(shù),performWorkOnRoot函數(shù)的第三個(gè)參數(shù)isExpired主要是用來判斷是否已超過執(zhí)行時(shí)間, 由于進(jìn)行的是同步操作, 所以默認(rèn)超過
performWorkOnRoot函數(shù)會(huì)先將rendering狀態(tài)設(shè)為true, 然后判斷是否異步或者超時(shí)進(jìn)行操作

function performWorkOnRoot(root, expirationTime, isExpired) {
  // 將rendering狀態(tài)設(shè)為true
  isRendering = true;

  // Check if this is async work or sync/expired work.
  if (deadline === null || isExpired) {
    // Flush work without yielding.
    // 同步
    var finishedWork = root.finishedWork;
    if (finishedWork !== null) {
      // This root is already complete. We can commit it.
      completeRoot(root, finishedWork, expirationTime);
    } else {
      root.finishedWork = null;
      // If this root previously suspended, clear its existing timeout, since
      // we"re about to try rendering again.
      var timeoutHandle = root.timeoutHandle;
      if (enableSuspense && timeoutHandle !== noTimeout) {
        root.timeoutHandle = noTimeout;
        // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
        cancelTimeout(timeoutHandle);
      }
      var isYieldy = false;
      renderRoot(root, isYieldy, isExpired);
      finishedWork = root.finishedWork;
      if (finishedWork !== null) {
        // We"ve completed the root. Commit it.
        completeRoot(root, finishedWork, expirationTime);
      }
    }
  } else {
    // Flush async work.異步操作
    ......
    }
  }

  isRendering = false;
}

11.renderRoot的產(chǎn)物會(huì)掛載到rootfinishWork屬性上, 首先performWorkOnRoot會(huì)先判斷rootfinishWork是否不為空, 如果存在的話則直接進(jìn)入commit的階段, 否則進(jìn)入到renderRoot函數(shù), 設(shè)置finishWork屬性
renderRoot有三個(gè)參數(shù), renderRoot(root, isYieldy, isExpired), 同步狀態(tài)下isYield的值是false,
renderRoot 先將 isWorking設(shè)為true,

renderRoot會(huì)先判斷是否是一個(gè)從新開始的root, 是的話會(huì)重置各個(gè)屬性

首先是resetStach()函數(shù), 對(duì)原有的進(jìn)行中的root任務(wù)中斷, 進(jìn)行存儲(chǔ)
緊接著將nextRootnextRendeExpirationTime重置, 同時(shí)創(chuàng)建第一個(gè)nextUnitOfWork, 也就是一個(gè)工作單元
這個(gè)nextUnitOfWork也是一個(gè)workProgress, 也是root.current的alternater屬性, 而它的alternate屬性則指向了root.current, 形成了一個(gè)雙緩沖池

if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) {
    // 判斷是否是一個(gè)從新開始的root
    resetStack();
    nextRoot = root;
    nextRenderExpirationTime = expirationTime;
    nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime);
    root.pendingCommitExpirationTime = NoWork;
    ....
    ....
  }

12.接著執(zhí)行wookLoop(isYield)函數(shù), 該函數(shù)通過循環(huán)執(zhí)行, 遍歷每一個(gè)nextUniOfWork,

function workLoop(isYieldy) {
  if (!isYieldy) {
    // Flush work without yielding
    while (nextUnitOfWork !== null) {
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  } else {
    // Flush asynchronous work until the deadline runs out of time.
    while (nextUnitOfWork !== null && !shouldYield()) {
      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    }
  }
}

13.performUnitOfWork 先 獲取 參數(shù)的alaernate屬性, 賦值給current,根據(jù)注釋的意思, workInProgress是作為一個(gè)代替品存在來操作, 然后會(huì)執(zhí)行下面這個(gè)語句

next = beginWork(current$$1, workInProgress, nextRenderExpirationTime);

14.beginWork主要根據(jù)workInprogresstag來做不同的處理, 并返回其child, 也就是下一個(gè)工作單元 如

, div作為一個(gè)工作單元, 處理完后就返回工作單元p, 同時(shí)收集他們的effect

next存在, 則返回到workLoop函數(shù)繼續(xù)循環(huán), 若不存在, 則執(zhí)行completeUnitOfWork(workInProgress)函數(shù)

completeUnitOfWork函數(shù), 會(huì)判斷是否有sibiling, 有則直接返回賦值給next, 否則判斷父fiber是否有sibiling, 一直循環(huán)到最上層父fiber為null, 執(zhí)行的同時(shí)會(huì)把effect逐級(jí)傳給父fiber

這個(gè)時(shí)候函數(shù)執(zhí)行完畢, 會(huì)返回到renderRoot函數(shù), renderRoot函數(shù)繼續(xù)往下走

首先將isWorking = false;執(zhí)行, 然后會(huì)判斷nextUnitWork是否為空, 否的話則將root.finishWork設(shè)為空(異步, 該任務(wù)未執(zhí)行完)并結(jié)束函數(shù)

isWorking = false;
if (nextUnitOfWork !== null) {
 onYield(root);
 return;
}

重置nextRoot

nextRoot = null;
interruptedBy = null;

賦值finishWork

var rootWorkInProgress = root.current.alternate;
onComplete(root, rootWorkInProgress, expirationTime);
function onComplete(root, finishedWork, expirationTime) {
  root.pendingCommitExpirationTime = expirationTime;
  root.finishedWork = finishedWork;
}

15.返回到performWorkOnRoot函數(shù), 進(jìn)入commit階段, 將rending狀態(tài)設(shè)為false,返回到performWork函數(shù), 繼續(xù)進(jìn)入循環(huán)執(zhí)行root, 直到所有root完成

重置各個(gè)狀態(tài)量, 如果還存在nextFlushedExpirationTime不為空, 則進(jìn)行scheduleCallbackWithExpirationTime函數(shù)異步操作

if (deadline !== null) {
    callbackExpirationTime = NoWork;
    callbackID = null;
  }
  // If there"s work left over, schedule a new callback.
  if (nextFlushedExpirationTime !== NoWork) {
    scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime);
  }

  // Clean-up.
  deadline = null;
  deadlineDidExpire = false;
結(jié)語

以上就是同步模式下的源碼分析~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/108956.html

相關(guān)文章

  • React Fiber源碼分析 第一篇

    摘要:系列文章源碼分析第一篇源碼分析第二篇同步模式源碼分析第三篇異步狀態(tài)源碼分析第四篇?dú)w納總結(jié)前言是在版本中的大更新,利用了閑余時(shí)間看了一些源碼,做個(gè)小記錄流程圖源碼分析先由編譯,調(diào)用,入?yún)?,打印出來可以看到,,分別代表著元素原生元素,回調(diào)函數(shù) 系列文章 React Fiber源碼分析 第一篇 React Fiber源碼分析 第二篇(同步模式) React Fiber源碼分析 第三篇(...

    amc 評(píng)論0 收藏0
  • React Fiber源碼分析 第四篇(歸納總結(jié))

    摘要:為什么網(wǎng)頁性能會(huì)變高要回答這個(gè)問題,需要回頭看是單線程的知識(shí)點(diǎn)。在分析的過程中,發(fā)現(xiàn)了的源碼中使用了很多鏈?zhǔn)浇Y(jié)構(gòu),回調(diào)鏈,任務(wù)鏈等,這個(gè)主要是為了增刪時(shí)性能比較高 系列文章 React Fiber源碼分析 第一篇 React Fiber源碼分析 第二篇(同步模式) React Fiber源碼分析 第三篇(異步狀態(tài)) React Fiber源碼分析 第四篇(歸納總結(jié)) 前言 Rea...

    jsdt 評(píng)論0 收藏0
  • 淺談React Fiber

    摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來很順暢。通過進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...

    izhuhaodev 評(píng)論0 收藏0
  • React Fiber源碼分析 第三篇(異步狀態(tài))

    摘要:系列文章源碼分析第一篇源碼分析第二篇同步模式源碼分析第三篇異步狀態(tài)源碼分析第四篇?dú)w納總結(jié)前言是在版本中的大更新,利用了閑余時(shí)間看了一些源碼,做個(gè)小記錄流程圖源碼分析調(diào)用時(shí),會(huì)調(diào)用的方法,同時(shí)將新的作為參數(shù)傳進(jìn)會(huì)先調(diào)用獲取一個(gè)維護(hù)兩個(gè)時(shí)間一個(gè) 系列文章 React Fiber源碼分析 第一篇 React Fiber源碼分析 第二篇(同步模式) React Fiber源碼分析 第三篇(...

    worldligang 評(píng)論0 收藏0
  • 全面了解 React 新功能: Suspense 和 Hooks

    摘要:他們的應(yīng)用是比較復(fù)雜的,組件樹也是非常龐大,假設(shè)有一千個(gè)組件要渲染,每個(gè)耗費(fèi)一千個(gè)就是由于是單線程的,這里都在努力的干活,一旦開始,中間就不會(huì)停。 悄悄的, React v16.7 發(fā)布了。 React v16.7: No, This Is Not The One With Hooks. showImg(https://segmentfault.com/img/bVblq9L?w=97...

    Baaaan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<