日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

React 源碼中最重要的部分,你知道有哪些嗎?

來源: 責編: 時間:2024-05-16 09:09:36 218觀看
導讀無論是并發模式,還是同步模式,最終要生成新的 Fiber Tree,都是通過遍歷 workInProgress 的方式去執行 performUnitOfWork。// 并發模式function workLoopConcurrent() { // Perform work until Scheduler asks us to yi

OnL28資訊網——每日最新資訊28at.com

無論是并發模式,還是同步模式,最終要生成新的 Fiber Tree,都是通過遍歷 workInProgress 的方式去執行 performUnitOfWork。OnL28資訊網——每日最新資訊28at.com

// 并發模式function workLoopConcurrent() {  // Perform work until Scheduler asks us to yield  while (workInProgress !== null && !shouldYield()) {    performUnitOfWork(workInProgress);  }}
// 同步function workLoopSync() {  // Already timed out, so perform work without checking if we need to yield.  while (workInProgress !== null) {    performUnitOfWork(workInProgress);  }}

需要特別注意的是這里的 workInProgress 表示當前正在執行的 Fiber 節點,他會在遞歸的過程中不斷改變指向,這里要結合我們之前章節中分享過的 Fiber Tree 的鏈表結構來理解。OnL28資訊網——每日最新資訊28at.com

if (next === null) {  // If this doesn't spawn new work, complete the current work.  completeUnitOfWork(unitOfWork);} else {  workInProgress = next;}

一、performUnitOfWork

該方法主要用于創建 Fiber Tree,是否理解 Fiber Tree 的構建過程,跟我們是否能做好性能優化有非常直接的關系,因此對我而言,這是 React 源碼中最重要的一個部分。OnL28資訊網——每日最新資訊28at.com

從他的第一行代碼我們就能知道,Fiber Tree 的創建是依賴于雙緩存策略。上一輪構建完成的 Fiber tree,在代碼中用 current 來表示。OnL28資訊網——每日最新資訊28at.com

正在構建中的 Fiber tree,在代碼中用 workInProgress 來表示,并且他們之間同層節點都用 alternate 相互指向。OnL28資訊網——每日最新資訊28at.com

current.alternate = workInProgress;workInProgress.alternate = current;

workInProgress 會基于 current 構建。OnL28資訊網——每日最新資訊28at.com

function performUnitOfWork(unitOfWork: Fiber): void {  const current = unitOfWork.alternate;  ...

整體的思路是從 current[rootFiber] 樹往下執行深度遍歷,在遍歷的過程中,會根據 key、props、context、state 等條件進行判斷,判斷結果如果發現節點沒有發生變化,那么就復用 current 的節點,如果發生了變化,則重新創建 Fiber 節點,并標記需要修改的類型,用于傳遞給 commitRoot。OnL28資訊網——每日最新資訊28at.com

二、beginWork

每一個被遍歷到的 Fiber 節點,會執行 beginWork 方法。OnL28資訊網——每日最新資訊28at.com

let next;if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {  startProfilerTimer(unitOfWork);  next = beginWork(current, unitOfWork, subtreeRenderLanes);  stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);} else {  next = beginWork(current, unitOfWork, subtreeRenderLanes);}

該方法根據傳入的 Fiber 節點創建子節點,并將這兩個節點連接起來。OnL28資訊網——每日最新資訊28at.com

function beginWork(  current: Fiber | null,  workInProgress: Fiber,  renderLanes: Lanes,): Fiber | null {...}

React 在 ReactFiberBeginWork.new.js 模塊中維護了一個全局的 didReceiveUpdate 變量,來表示當前節點是否需要更新。OnL28資訊網——每日最新資訊28at.com

let didReceiveUpdate: boolean = false;

在 beginWork 的執行過程中,會經歷一些判斷來確認 didReceiveUpdate 的值,從而判斷該 Fiber 節點是否需要重新執行。OnL28資訊網——每日最新資訊28at.com

if (current !== null) {    const oldProps = current.memoizedProps;    const newProps = workInProgress.pendingProps;    if (      oldProps !== newProps ||      hasLegacyContextChanged() ||      // Force a re-render if the implementation changed due to hot reload:      (__DEV__ ? workInProgress.type !== current.type : false)    ) {      // If props or context changed, mark the fiber as having performed work.      // This may be unset if the props are determined to be equal later (memo).      didReceiveUpdate = true;    } else {

這里比較的是 props 和 context 是否發生了變化。當他們其中一個變化時,則將 didReceiveUpdate 設置為 true。OnL28資訊網——每日最新資訊28at.com

這里的 hasLegacyContextChanged()  兼容的是舊版本 的 context,新版本的 context 是否發生變化會反應到 pending update 中,也就是使用下面的 checkScheduledUpdateOrContext 來查看是否有更新的調度任務。OnL28資訊網——每日最新資訊28at.com

當 props 和 context 都沒有發生變化,并且也不存在對應的調度任務時,將其設置為 false。OnL28資訊網——每日最新資訊28at.com

如果有 state/context 發生變化,則會存在調度任務。OnL28資訊網——每日最新資訊28at.com

} else {  // Neither props nor legacy context changes. Check if there's a pending  // update or context change.  const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(    current,    renderLanes,  );  if (    !hasScheduledUpdateOrContext &&    // If this is the second pass of an error or suspense boundary, there    // may not be work scheduled on `current`, so we check for this flag.    (workInProgress.flags & DidCapture) === NoFlags  ) {    // No pending updates or context. Bail out now.    didReceiveUpdate = false;    return attemptEarlyBailoutIfNoScheduledUpdate(      current,      workInProgress,      renderLanes,    );  }

這里有一個很關鍵的點,就在于當方法進入到 attemptEarlyBailoutIfNoScheduledUpdate 去判斷子節點是否可以 bailout 時,他并沒有比較子節點的 props。OnL28資訊網——每日最新資訊28at.com

核心的邏輯在 bailoutOnAlreadyFinishedWork 中。OnL28資訊網——每日最新資訊28at.com

{  ...  // 判斷子節點是否有 pending 任務要做  if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {    // The children don't have any work either. We can skip them.    return null  }  // This fiber doesn't have work, but its subtree does. Clone the child  // fibers and continue.  cloneChildFibers(current, workInProgress);  return workInProgress.child;}

所以這里有一個很重要的思考就是為什么判斷子節點是否發生變化時,并沒有去比較 props,這是性能優化策略的關鍵一步,結合我們之前講的性能優化策略去理解,你就能知道答案。OnL28資訊網——每日最新資訊28at.com

回到 beginWork, 后續的邏輯會根據不同的 tag,創建不同類型的 Fiber 節點。OnL28資訊網——每日最新資訊28at.com

switch (workInProgress.tag) {  case IndeterminateComponent: {    return mountIndeterminateComponent(      current,      workInProgress,      workInProgress.type,      renderLanes,    );  }  case LazyComponent: {    const elementType = workInProgress.elementType;    return mountLazyComponent(      current,      workInProgress,      elementType,      renderLanes,    );  }  case FunctionComponent: {    const Component = workInProgress.type;    const unresolvedProps = workInProgress.pendingProps;    const resolvedProps =      workInProgress.elementType === Component        ? unresolvedProps        : resolveDefaultProps(Component, unresolvedProps);    return updateFunctionComponent(      current,      workInProgress,      Component,      resolvedProps,      renderLanes,    );  }  case ClassComponent: {    const Component = workInProgress.type;    const unresolvedProps = workInProgress.pendingProps;    const resolvedProps =      workInProgress.elementType === Component        ? unresolvedProps        : resolveDefaultProps(Component, unresolvedProps);    return updateClassComponent(      current,      workInProgress,      Component,      resolvedProps,      renderLanes,    );  }  case HostRoot:    return updateHostRoot(current, workInProgress, renderLanes);  case HostComponent:    return updateHostComponent(current, workInProgress, renderLanes);  case HostText:    return updateHostText(current, workInProgress);  case SuspenseComponent:    return updateSuspenseComponent(current, workInProgress, renderLanes);  case HostPortal:    return updatePortalComponent(current, workInProgress, renderLanes);  case ForwardRef: {    const type = workInProgress.type;    const unresolvedProps = workInProgress.pendingProps;    const resolvedProps =      workInProgress.elementType === type        ? unresolvedProps        : resolveDefaultProps(type, unresolvedProps);    return updateForwardRef(      current,      workInProgress,      type,      resolvedProps,      renderLanes,    );  }    // ...    case MemoComponent: {    const type = workInProgress.type;    const unresolvedProps = workInProgress.pendingProps;    // Resolve outer props first, then resolve inner props.    let resolvedProps = resolveDefaultProps(type, unresolvedProps);    if (__DEV__) {      if (workInProgress.type !== workInProgress.elementType) {        const outerPropTypes = type.propTypes;        if (outerPropTypes) {          checkPropTypes(            outerPropTypes,            resolvedProps, // Resolved for outer only            'prop',            getComponentNameFromType(type),          );        }      }    }    resolvedProps = resolveDefaultProps(type.type, resolvedProps);    return updateMemoComponent(      current,      workInProgress,      type,      resolvedProps,      renderLanes,    );  }}// ... 其他類型

我們重點關注 updateFunctionComponent 的執行邏輯,可以發現,當 didReceiveUpdate 為 false 時,會執行 bailout 跳過創建過程。OnL28資訊網——每日最新資訊28at.com

if (current !== null && !didReceiveUpdate) {  bailoutHooks(current, workInProgress, renderLanes);  return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);}

如果無法 bailout,則最后執行 reconcileChildren 創建新的子節點。OnL28資訊網——每日最新資訊28at.com

reconcileChildren(current, workInProgress, nextChildren, renderLanes);  return workInProgress.child;

另外我們還應該關注 updateMemoComponent 中的邏輯。該邏輯通過淺比較函數 shallowEqual 來比較更新前后兩個 props 的差異。當比較結果為 true 時,也是調用 bailout 跳過創建。OnL28資訊網——每日最新資訊28at.com

而不是沿用 didReceiveUpdate 的結果。OnL28資訊網——每日最新資訊28at.com

if (!hasScheduledUpdateOrContext) {  // This will be the props with resolved defaultProps,  // unlike current.memoizedProps which will be the unresolved ones.  const prevProps = currentChild.memoizedProps;  // Default to shallow comparison  let compare = Component.compare;  compare = compare !== null ? compare : shallowEqual;  if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);  }}

二、completeWork

在 performUnitOfWork 執行過程中,當發現當前節點已經沒有子節點了,就會調用 completeUnitOfWork 方法。OnL28資訊網——每日最新資訊28at.com

if (next === null) {  // If this doesn't spawn new work, complete the current work.  completeUnitOfWork(unitOfWork);

該方法主要用于執行 completeWork。completeWork 主要的作用是用于創建與 Fiber 節點對應的 DOM 節點。OnL28資訊網——每日最新資訊28at.com

這里創建的 DOM 節點并沒有插入到 HTML 中,還存在于內存里。OnL28資訊網——每日最新資訊28at.com

const instance = createInstance(  type,  newProps,  rootContainerInstance,  currentHostContext,  workInProgress,);appendAllChildren(instance, workInProgress, false, false);

由于 completeWork 的執行是從葉子節點,往根節點執行,因此,每次我們將新創建的節點 append 到父節點,執行到最后 rootFiber 時,一個完整的 DOM 樹就已經構建完成了。OnL28資訊網——每日最新資訊28at.com

completeWork 的執行順序是一個回溯的過程。OnL28資訊網——每日最新資訊28at.com

當然,Fiber 節點與 DOM 節點之間,也會保持一一對應的引用關系,因此在更新階段,我們能夠輕易的判斷和復用已經存在的 DOM 節點從而避免重復創建。OnL28資訊網——每日最新資訊28at.com

四、遍歷順序

beginWork 和 completeWork 的執行順序理解起來比較困難,為了便于理解,我們這里用一個圖示來表達。OnL28資訊網——每日最新資訊28at.com

例如有這樣一個結構的節點。OnL28資訊網——每日最新資訊28at.com

<div id="root">  <div className="1">    <div className="1-1">1-1</div>    <div className="1-2">1-2</div>    <div className="1-3">      <div className="1-3-1">1-3-1</div>    </div>  </div>  <div className="2">2</div>  <div className="3">3</div></div>

beginWork 的執行是按照 Fiber 節點的鏈表深度遍歷執行。OnL28資訊網——每日最新資訊28at.com

completeWork 則是當 fiber.next === null 時開始執行,他一個從葉子節點往根節點執行的回溯過程。當葉子節點被執行過后,則對葉子節點的父節點執行 completeWork。OnL28資訊網——每日最新資訊28at.com

下圖就是上面 demo 的執行順序。OnL28資訊網——每日最新資訊28at.com

其中藍色圓代表對應節點的 beginWork 執行。黃色圓代表對應節點的 completeWork 執行。OnL28資訊網——每日最新資訊28at.com

OnL28資訊網——每日最新資訊28at.com

五、總結

beginWork 與 completeWork 的執行是 React 源碼中最重要的部分,理解他們的核心邏輯能有效幫助我們做好項目的性能優化。因此在學習他們的過程中,應該結合實踐去思考優化策略。OnL28資訊網——每日最新資訊28at.com

不過性能優化的方式在我們之前的章節中已經詳細介紹過,因此這里帶大家閱讀源碼更多的是做一個驗證,去揭開源碼的神秘面紗。OnL28資訊網——每日最新資訊28at.com

到這篇文章這里,React 原理的大多數重要邏輯我們在知命境的文章都已經給大家分享過了,其中包括同步更新邏輯,異步更新邏輯,任務優先級隊列,任務調度,Fiber 中的各種鏈表結構,各種比較方式的成本,包括本文介紹的 Fiber tree 的構建過程,大家可以把這些零散的文章串起來總結一下,有能力的可以自己在閱讀源碼時結合我分享的內容進一步擴展和完善。OnL28資訊網——每日最新資訊28at.com

閱讀源碼是一個高投入,低回報的過程,希望我的這些文章能有效幫助大家以更低的時間成本獲得更高的知識回報。OnL28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-88379-0.htmlReact 源碼中最重要的部分,你知道有哪些嗎?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 常見,但是總回答不好的面試題:JS 模塊化以及模塊打包器

下一篇: SpringBoot3.x 和 WebSocket 在物聯網設備管理中的應用

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
国产精品久久久久久久午夜片| **网站欧美大片在线观看| 校园春色国产精品| 日韩视频免费在线| 在线免费观看欧美| 国产精品久久久久久久久久久久| 欧美成人精品h版在线观看| 亚洲欧美亚洲| 日韩一区二区久久| 最新国产拍偷乱拍精品| 一色屋精品亚洲香蕉网站| 国产欧美日韩视频一区二区| 欧美三区在线观看| 欧美三级中文字幕在线观看| 欧美剧在线免费观看网站| 美日韩在线观看| 久久天天狠狠| 久久久久国产一区二区三区四区| 欧美一区二区视频在线| 午夜日韩在线观看| 欧美亚洲一区| 欧美专区第一页| 亚洲欧美自拍偷拍| 午夜精品一区二区三区四区| 午夜精品短视频| 欧美一级在线亚洲天堂| 欧美一区亚洲二区| 久久国产日韩欧美| 久久久另类综合| 老巨人导航500精品| 欧美成人精品不卡视频在线观看| 欧美成人资源网| 欧美—级在线免费片| 欧美精品偷拍| 欧美午夜激情在线| 国产精品一二三四区| 国产欧美日韩免费看aⅴ视频| 国产视频在线观看一区二区| 国产一区在线免费观看| 激情91久久| 亚洲国产老妈| 日韩一级大片在线| 亚洲一区二区免费视频| 欧美亚洲三级| 久久免费偷拍视频| 欧美国产免费| 欧美午夜免费| 国产香蕉久久精品综合网| 韩日欧美一区二区| 亚洲区欧美区| 亚洲视频二区| 欧美在线观看网站| 美女视频一区免费观看| 欧美另类视频| 国产精品剧情在线亚洲| 国产一区二区三区无遮挡| 亚洲成在人线av| 一本色道久久综合一区 | 影音先锋日韩精品| 亚洲精品久久久久久下一站| 中文欧美在线视频| 国产精品r级在线| 国产酒店精品激情| 影音先锋中文字幕一区| 日韩视频―中文字幕| 亚洲视频精品在线| 久久久久九九九九| 欧美剧在线免费观看网站| 国产精品日韩在线观看| 在线成人中文字幕| 亚洲图片在线观看| 久久天堂国产精品| 欧美网站在线观看| 狠狠色丁香久久婷婷综合_中| 亚洲精品一区二区三区婷婷月 | 日韩亚洲欧美综合| 欧美亚洲综合在线| 欧美激情一区二区三区在线视频观看| 国产精品v欧美精品v日韩| 国产在线视频欧美| 99视频有精品| 久久久精品国产一区二区三区| 欧美屁股在线| 激情91久久| 亚洲综合99| 欧美寡妇偷汉性猛交| 国产女主播一区| 亚洲精品在线视频观看| 久久国产一区二区| 欧美视频在线观看 亚洲欧| 激情欧美一区二区三区| 亚洲在线第一页| 欧美成人精精品一区二区频| 国产婷婷97碰碰久久人人蜜臀| 亚洲麻豆国产自偷在线| 久久久综合免费视频| 国产精品人人做人人爽| 亚洲精品综合久久中文字幕| 久久久国产一区二区| 国产精品久久久久aaaa樱花| 亚洲激情社区| 久久婷婷激情| 国产日韩欧美在线播放不卡| 中文国产亚洲喷潮| 欧美极品一区二区三区| 激情久久久久| 欧美亚洲一级片| 国产精品国产馆在线真实露脸 | 久久精品国产成人| 欧美视频免费在线观看| 91久久久久久| 麻豆亚洲精品| 黄色av一区| 欧美中日韩免费视频| 国产精品乱码人人做人人爱| 夜夜嗨av色综合久久久综合网| 久久天堂av综合合色| 国产性色一区二区| 性色av一区二区三区红粉影视| 欧美日韩综合久久| 99精品黄色片免费大全| 欧美福利在线| 亚洲国产精品免费| 久久综合成人精品亚洲另类欧美| 国产性做久久久久久| 性色av一区二区三区| 国产精品私拍pans大尺度在线| 亚洲香蕉成视频在线观看| 欧美日韩一区高清| 99精品国产福利在线观看免费| 欧美国产欧美亚洲国产日韩mv天天看完整 | 亚洲黄色免费网站| 蜜桃av噜噜一区二区三区| 一区二区视频免费在线观看| 久久久久综合| 在线观看日韩精品| 另类天堂视频在线观看| 在线看无码的免费网站| 久久午夜电影网| 在线观看亚洲专区| 免费视频最近日韩| 亚洲精品社区| 欧美日韩在线观看一区二区三区| 一区二区av在线| 欧美性猛交xxxx乱大交退制版| 一区二区三区日韩精品| 国产精品久久久久久五月尺| 亚洲自拍偷拍网址| 国产日韩欧美综合精品| 久久精品久久综合| 亚洲二区免费| 欧美精品91| 在线视频亚洲欧美| 国产美女精品免费电影| 欧美伊久线香蕉线新在线| 韩国av一区| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲国产欧美国产综合一区| 欧美极品色图| 亚洲一区日本| 国产亚洲人成a一在线v站| 久久久免费精品视频| 亚洲激情视频在线播放| 欧美色欧美亚洲高清在线视频| 亚洲一区精品视频| 狠狠噜噜久久| 欧美国产1区2区| 亚洲深夜福利网站| 国产小视频国产精品| 美女精品自拍一二三四| 日韩亚洲在线观看| 国产欧美亚洲精品| 免费视频一区二区三区在线观看| 日韩一级黄色片| 国产美女精品一区二区三区| 久久夜色精品| 一区二区三区三区在线| 国产日韩精品一区二区| 免费成人毛片| 亚洲午夜精品久久| 国语自产在线不卡| 欧美乱妇高清无乱码| 亚洲欧美日韩在线综合| 在线精品视频一区二区三四| 欧美日韩成人综合| 欧美在线免费视频| 亚洲精品乱码久久久久久按摩观| 国产精品成人一区二区网站软件 | 久久精品一区二区| 亚洲免费观看高清完整版在线观看| 国产精品二区二区三区| 久久亚洲私人国产精品va| 一区二区三区四区蜜桃| 合欧美一区二区三区| 欧美经典一区二区| 欧美亚洲三区| 亚洲美女区一区| 国模吧视频一区| 欧美日韩一区二区国产| 久久天天综合| 亚洲午夜小视频| 亚洲黄色影院| 国产一区二区视频在线观看| 欧美日韩ab|