国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

React16源碼: React中的performWork的源碼實現(xiàn)

這篇具有很好參考價值的文章主要介紹了React16源碼: React中的performWork的源碼實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

performWork


1 )概述

  • performWork 涉及到在調(diào)度完成,或者同步任務(wù)進來之后整個 root 節(jié)點鏈條如何更新
  • 怎么更新一棵 Fiber 樹,它的每一個節(jié)點是如何被遍歷到,以及如何進行更新操作
  • A. 在執(zhí)行 performWork 時候,是否有 deadline 的區(qū)分
    • deadline 是通過 reactschedule 它的一個時間片,更新的過程當中
    • 產(chǎn)生的一個叫做 deadlineobject 的對象
    • 它可以用來判斷我們在一幀的渲染時間內(nèi)留給react進行fiber樹渲染的時間還有沒有
  • B.循環(huán)渲染root的條件
    • 一個應(yīng)用當中可能會有多個root節(jié)點
    • 同時每一個root節(jié)點上面呢又會有不同優(yōu)先級的任務(wù)產(chǎn)生
    • 要循環(huán)去遍歷各個不同的root節(jié)點
    • 以及他們的不同的優(yōu)先級的任務(wù),然后按照優(yōu)先級去一個個去更新
    • 這個循環(huán)它如何建立,如何判斷這個循環(huán)是否成立的條件
  • C.超過時間片之后的一個處理
    • 在deadline到了之后,就是我們這一幀的渲染時間已經(jīng)到了
    • 我們需要把js的執(zhí)行權(quán)又交回給瀏覽器,這個時候又該怎么做

2 )源碼

定位到 packages/react-reconciler/src/ReactFiberScheduler.js文章來源地址http://www.zghlxwxcb.cn/news/detail-796852.html

function performAsyncWork() {
  try {
    if (!shouldYieldToRenderer()) {
      // The callback timed out. That means at least one update has expired.
      // Iterate through the root schedule. If they contain expired work, set
      // the next render expiration time to the current time. This has the effect
      // of flushing all expired work in a single batch, instead of flushing each
      // level one at a time.
      if (firstScheduledRoot !== null) {
        recomputeCurrentRendererTime();
        let root: FiberRoot = firstScheduledRoot;
        do {
          didExpireAtExpirationTime(root, currentRendererTime);
          // The root schedule is circular, so this is never null.
          root = (root.nextScheduledRoot: any);
        } while (root !== firstScheduledRoot);
      }
    }
    performWork(NoWork, true);
  } finally {
    didYield = false;
  }
}


function performSyncWork() {
  performWork(Sync, null);
}

function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {
  deadline = dl;

  // Keep working on roots until there's no more work, or until we reach
  // the deadline.
  findHighestPriorityRoot();

  if (deadline !== null) {
    recomputeCurrentRendererTime();
    currentSchedulerTime = currentRendererTime;

    if (enableUserTimingAPI) {
      const didExpire = nextFlushedExpirationTime < currentRendererTime;
      const timeout = expirationTimeToMs(nextFlushedExpirationTime);
      stopRequestCallbackTimer(didExpire, timeout);
    }

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

  // We're done flushing work. Either we ran out of time in this callback,
  // or there's no more work left with sufficient priority.

  // If we're inside a callback, set this to false since we just completed it.
  if (deadline !== null) {
    callbackExpirationTime = NoWork;
    callbackID = null;
  }
  // If there's work left over, schedule a new callback.
  if (nextFlushedExpirationTime !== NoWork) {
    scheduleCallbackWithExpirationTime(
      ((nextFlushedRoot: any): FiberRoot),
      nextFlushedExpirationTime,
    );
  }

  // Clean-up.
  deadline = null;
  deadlineDidExpire = false;

  finishRendering();
}
  • performAsyncWork, performSyncWork, performWork 三個方法連在一起
  • 對于 performSyncWork 直接 調(diào)用 performWork(Sync, null); 就一行代碼
  • performAsyncWork 就相對復(fù)雜,是通過 react scheduler 調(diào)度回來的
    • 參數(shù)是 deadline 對象 dl
    • 本質(zhì)上只有一個 if判斷 和 執(zhí)行 performWork 方法
    • 在if判斷中, recomputeCurrentRendererTime 這個方法不涉及主要流程,跳過
      • 在找到 root 之后,執(zhí)行 didExpireaTexpirationTime 標記在root節(jié)點上的一些變量
        // packages/react-reconciler/src/ReactFiberPendingPriority.js
        export function didExpireAtExpirationTime(
          root: FiberRoot,
          currentTime: ExpirationTime,
        ): void {
          const expirationTime = root.expirationTime;
          // 有任務(wù),但任務(wù)過期
          if (expirationTime !== NoWork && currentTime >= expirationTime) {
            // The root has expired. Flush all work up to the current time.
            root.nextExpirationTimeToWorkOn = currentTime; // 掛載 當前時間 作為 nextExpirationTimeToWorkOn 屬性
          }
        }
        
      • 之后,一個do while 找最終的 root
    • 之后,執(zhí)行 performWork(NoWork, dl)
      • NoWork 是 0
      • export const NoWork = 0
  • performWork
    • 有兩個參數(shù),minExpirationTime: ExpirationTime, dl: Deadline | null
    • findHighestPriorityRoot 這個方法
      function findHighestPriorityRoot() {
        let highestPriorityWork = NoWork;
        let highestPriorityRoot = null;
        // 這個if表示仍存在節(jié)點更新情況
        if (lastScheduledRoot !== null) {
          let previousScheduledRoot = lastScheduledRoot;
          let root = firstScheduledRoot;
          // 存在 root 就進行循環(huán)
          while (root !== null) {
            const remainingExpirationTime = root.expirationTime;
            // 這個if判斷表示,是沒有任何更新的
            if (remainingExpirationTime === NoWork) {
              // This root no longer has work. Remove it from the scheduler.
      
              // TODO: This check is redudant, but Flow is confused by the branch
              // below where we set lastScheduledRoot to null, even though we break
              // from the loop right after.
              invariant(
                previousScheduledRoot !== null && lastScheduledRoot !== null,
                'Should have a previous and last root. This error is likely ' +
                  'caused by a bug in React. Please file an issue.',
              );
              // 這種情況,只有一個 root 節(jié)點
              if (root === root.nextScheduledRoot) {
                // This is the only root in the list.
                root.nextScheduledRoot = null;
                firstScheduledRoot = lastScheduledRoot = null;
                break;
              } else if (root === firstScheduledRoot) {
                // 這時候 root 就沒用了,可以刪除了,獲取 next
                // This is the first root in the list.
                const next = root.nextScheduledRoot;
                firstScheduledRoot = next;
                lastScheduledRoot.nextScheduledRoot = next;
                root.nextScheduledRoot = null;
              } else if (root === lastScheduledRoot) {
                // 這個時候,root是最后一個
                // This is the last root in the list.
                lastScheduledRoot = previousScheduledRoot;
                lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
                root.nextScheduledRoot = null;
                break;
              } else {
                // 移除 中間的 root.nextScheduledRoot 節(jié)點
                previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot;
                root.nextScheduledRoot = null;
              }
              root = previousScheduledRoot.nextScheduledRoot;
            } else {
              // 判斷優(yōu)先級,更新更高優(yōu)先級
              if (
                highestPriorityWork === NoWork ||
                remainingExpirationTime < highestPriorityWork
              ) {
                // Update the priority, if it's higher
                highestPriorityWork = remainingExpirationTime;
                highestPriorityRoot = root;
              }
              if (root === lastScheduledRoot) {
                break;
              }
              if (highestPriorityWork === Sync) {
                // Sync is highest priority by definition so
                // we can stop searching.
                break;
              }
              previousScheduledRoot = root;
              root = root.nextScheduledRoot;
            }
          }
        }
        // 處理更新后的 highestPriorityRoot 和 highestPriorityWork
        nextFlushedRoot = highestPriorityRoot;
        nextFlushedExpirationTime = highestPriorityWork;
      }
      
    • 看下 deadine 不為 null 時的情況
      • 這是異步的情況
      • 主要看 while 里的 (!deadlineDidExpire || currentRendererTime >= nextFlushedExpirationTime)
        • !deadlineDidExpire 表示時間片還有剩余時間
        • nextFlushedExpirationTime 是現(xiàn)在要輸出任務(wù)的過期時間
          • currentRendererTime >= nextFlushedExpirationTime
          • 說明 當前 render 時間 比 過期時間大,已經(jīng)超時了,需要強制輸出
        • 之后執(zhí)行 performWorkOnRoot
          • 關(guān)于這個函數(shù),主要關(guān)注第三個參數(shù)
          • 默認是 true
          • 對于異步情況,值為: currentRendererTime >= nextFlushedExpirationTime
            • 任務(wù)過期,則為 true, 否則為 false
        • 進入 這個函數(shù)
          function performWorkOnRoot(
            root: FiberRoot,
            expirationTime: ExpirationTime,
            isExpired: boolean, // 是否過期,這個方法里一定有針對過期任務(wù)的強制更新
          ) {
            invariant(
              !isRendering,
              'performWorkOnRoot was called recursively. This error is likely caused ' +
                'by a bug in React. Please file an issue.',
            );
          
            isRendering = true; // 注意這里和函數(shù)結(jié)束
          
            // Check if this is async work or sync/expired work.
            // deadline === null  是 Sync的情況,isExpired 是過期的情況
            if (deadline === null || isExpired) {
              // Flush work without yielding.
              // TODO: Non-yieldy work does not necessarily imply expired work. A renderer
              // may want to perform some work without yielding, but also without
              // requiring the root to complete (by triggering placeholders).
          
              let finishedWork = root.finishedWork;
              if (finishedWork !== null) {
                // This root is already complete. We can commit it.
                completeRoot(root, finishedWork, expirationTime); // 有 finishedWork 直接 completeRoot
              } else {
                root.finishedWork = null;
                // If this root previously suspended, clear its existing timeout, since
                // we're about to try rendering again.
                const timeoutHandle = root.timeoutHandle;
                // 處理 timeoutHandle 的情況,跳過
                if (timeoutHandle !== noTimeout) {
                  root.timeoutHandle = noTimeout;
                  // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
                  cancelTimeout(timeoutHandle);
                }
                // 在這個條件下,不可中斷 因為在上層if框架下,要么是 Sync的任務(wù),要么是 過期的任務(wù)需要立即執(zhí)行
                const isYieldy = false;
                renderRoot(root, isYieldy, isExpired);
                finishedWork = root.finishedWork;
                if (finishedWork !== null) {
                  // We've completed the root. Commit it.
                  completeRoot(root, finishedWork, expirationTime);
                }
              }
            } else {
              // 這里匹配 Async 異步任務(wù),和上面Sync的任務(wù)流程基本差不多
              // Flush async work.
              let finishedWork = root.finishedWork;
              // 一開始進來判斷這個 finishedWork,有可能在上一個時間片中,renderRoot執(zhí)行完了,但是,沒有時間去執(zhí)行 completeRoot 了
              // 需要再下次異步調(diào)度的時候進來,如果有 finishedWork 則先 completeRoot
              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.
                const timeoutHandle = root.timeoutHandle;
                if (timeoutHandle !== noTimeout) {
                  root.timeoutHandle = noTimeout;
                  // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
                  cancelTimeout(timeoutHandle);
                }
                // 這個任務(wù)是可以中斷的
                const isYieldy = true;
                renderRoot(root, isYieldy, isExpired);
                finishedWork = root.finishedWork;
                // finishedWork 有可能為 null, 中斷了就沒有完成任務(wù)
                if (finishedWork !== null) {
                  // We've completed the root. Check the deadline one more time
                  // before committing.
                  // 先判斷是否需要跳出,這時候時間片可能已經(jīng)用完,如果沒有用完,執(zhí)行 completeRoot
                  if (!shouldYield()) {
                    // Still time left. Commit the root.
                    completeRoot(root, finishedWork, expirationTime);
                  } else {
                    // There's no time left. Mark this root as complete. We'll come
                    // back and commit it later.
                    // 需要跳出,則賦值 finishedWork,注意這里不執(zhí)行 completeRoot,因為沒有時間了,需要等待下個時間片進來才能執(zhí)行
                    root.finishedWork = finishedWork;
                  }
                }
              }
            }
          
            isRendering = false;
          }
          
        • 執(zhí)行 findHighestPriorityRoot
        • currentSchedulerTime = currentRendererTime
    • 看下 deadine 為 null 時的情況
      • 這是同步的情況
      • while(nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || minExpirationTime >= nextFlushedExpirationTime))
        • 對于 perfromSyncWork 來說,minExpirationTime 是 1,1 >= nextFlushedExpirationTime 說明 只有 Sync(1)的情況,或者 NoWork,所以 nextFlushedExpirationTime 只有是1的情況
        • 相當于在 perfromSyncWork 的時候,只會執(zhí)行 root.expirationTime 是 Sync 的任務(wù),也就是說是同步更新的更新,才會在這里繼續(xù)執(zhí)行,這樣和 SyncWork 這函數(shù)名匹配
        • 在這種情況下,調(diào)用 performWorkOnRootfindHighestPriorityRoot 執(zhí)行掉 Sync的任務(wù)
  • 注意,在 performWork 上兩個循環(huán)的判斷條件
  • 以及傳入 performWorkOnRoot的第三個參數(shù)的意義

到了這里,關(guān)于React16源碼: React中的performWork的源碼實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • React16源碼: React中的beginWork的源碼實現(xiàn)

    beginWork 1 )概述 在 renderRoot 之后,要對我們的 Fiber 樹每一個節(jié)點進行對應(yīng)的更新 更新節(jié)點的一個入口方法,就是 beginWork 這個入口方法會有幫助我們?nèi)?yōu)化整棵樹的更新過程 react 它的節(jié)點其實是非常多的,如果每一次子節(jié)點的一個更新 就需要每一個節(jié)點都執(zhí)行一遍更新的話

    2024年01月20日
    瀏覽(24)
  • React16源碼: React中的updateHostRoot的源碼實現(xiàn)

    HostRoot 的更新 1 )概述 HostRoot 是一個比較特殊的節(jié)點, 因為在一個react應(yīng)用當中 它只會有一個 HostRoot , 它對應(yīng)的 Fiber 對象是我們的 RootFiber 對象 重點在于它的更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L612 HostRoot 創(chuàng)建更新的過程就是在 ReactFiberReconcile

    2024年01月22日
    瀏覽(29)
  • React16源碼: React中的IndeterminateComponent的源碼實現(xiàn)

    IndeterminateComponent 1 )概述 這是一個比較特殊的component的類型, 就是還沒有被指定類型的component 在一個fibrer被創(chuàng)建的時候,它的tag可能會是 IndeterminateComponent 在 packages/react-reconciler/src/ReactFiber.js 中,有一個方法 createFiberFromTypeAndProps 中,一開始就聲明了 在最終調(diào)用 createFibe

    2024年01月21日
    瀏覽(20)
  • React16源碼: React中的completeUnitOfWork的源碼實現(xiàn)

    React16源碼: React中的completeUnitOfWork的源碼實現(xiàn)

    completeUnitOfWork 1 )概述 各種不同類型組件的一個更新過程對應(yīng)的是在執(zhí)行 performUnitOfWork 里面的 beginWork 階段 它是去向下遍歷一棵 fiber 樹的一側(cè)的子節(jié)點,然后遍歷到葉子節(jié)點為止,以及 return 自己 child 的這種方式 在 performUnitOfWork 里面,還有一個方法叫做 completeUnitOfWork 在

    2024年01月23日
    瀏覽(33)
  • React16源碼: React中的setState和forceUpdate源碼實現(xiàn)

    setState 和 forceUpdate 1 ) 概述 通過 class component 內(nèi)部的 setState ,以及 forceUpdate 去更新一個組件的過程 在react的應(yīng)用當中,我們只有 ReactDOM.render setState ,以及 forceUpdate 這幾種種方式去更新react的應(yīng)用是合理的,其他沒有什么特別常用的方式去更新了 而且react官方推薦的也是用

    2024年01月25日
    瀏覽(22)
  • React16源碼: React中的HostComponent & HostText的源碼實現(xiàn)

    HostComponent HostText 1 )概述 HostComponent 就是我們dom原生的這些節(jié)點, 如: div, span, p 標簽這種 使用的是小寫字母開頭的這些節(jié)點一般都認為它是一個 HostComponent HostText ,它是單純的文本節(jié)點 主要關(guān)注它們的一個更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js 進

    2024年01月24日
    瀏覽(19)
  • React16源碼: React中的reconcileChildIterator和reconcileChildrenArray的源碼實現(xiàn)

    reconcileChildIterator 和 reconcileChildrenArray 1 )概述 在react更新某一個節(jié)點的時候,要根據(jù)這個節(jié)點,它的類型去獲取它的children 比如說如果是 Function Component,它要調(diào)用這個 component 計算出它的return的屬性 return的屬性可能是一個數(shù)組,可能是單個的 ReactElement,可能是 number, string

    2024年01月20日
    瀏覽(46)
  • React16源碼: React中的不同的expirationTime的源碼實現(xiàn)

    不同的 expirationTime 1 )概述 在React中不僅僅有異步任務(wù) 大部分情況下都是同步的任務(wù),所以會有不同 expirationTime 的存在 2 )種類 A. Sync 模式,優(yōu)先級最高 任務(wù)創(chuàng)建完成之后,立馬更新到真正的dom里面 是一個創(chuàng)建即更新的流程 B. Async 模式, 異步模式 會有一個調(diào)度 包含一系列

    2024年02月01日
    瀏覽(19)
  • React16源碼: React中的PortalComponent創(chuàng)建, 調(diào)和, 更新的源碼實現(xiàn)

    PortalComponent 1 )概述 React Portal之所以叫Portal,因為做的就是和“傳送門”一樣的事情 render到一個組件里面去,實際改變的是網(wǎng)頁上另一處的DOM結(jié)構(gòu) 主要關(guān)注 portal的創(chuàng)建, 調(diào)和, 更新過程 2 )源碼 定位到 packages/react-dom/src/client/ReactDOM.js#L576 這里調(diào)用的是 ReactPortal.createPortal ,

    2024年01月21日
    瀏覽(25)
  • React16源碼: React中的update和updateQueue的源碼實現(xiàn)

    React中的update和updateQueue 1 )概述 在 ReactDOM.render 過程中,還需要創(chuàng)建一個 update 對象 update 用于記錄組件狀態(tài)的改變的一個對象,它存放于Fiber對象的 updateQueue 中 updateQueue ,它是一個單向鏈表的結(jié)構(gòu),一次整體的更新過程當中 可能在這個queue里會存在多 Update 在這次更新的過

    2024年02月02日
    瀏覽(14)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包