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

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

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

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

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

無論是并發模式,還是同步模式,最終要生成新的 Fiber Tree,都是通過遍歷 workInProgress 的方式去執行 performUnitOfWork。n8n28資訊網——每日最新資訊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 的鏈表結構來理解。n8n28資訊網——每日最新資訊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 源碼中最重要的一個部分。n8n28資訊網——每日最新資訊28at.com

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

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

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

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

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

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

二、beginWork

每一個被遍歷到的 Fiber 節點,會執行 beginWork 方法。n8n28資訊網——每日最新資訊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 節點創建子節點,并將這兩個節點連接起來。n8n28資訊網——每日最新資訊28at.com

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

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

let didReceiveUpdate: boolean = false;

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

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

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

如果有 state/context 發生變化,則會存在調度任務。n8n28資訊網——每日最新資訊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。n8n28資訊網——每日最新資訊28at.com

核心的邏輯在 bailoutOnAlreadyFinishedWork 中。n8n28資訊網——每日最新資訊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,這是性能優化策略的關鍵一步,結合我們之前講的性能優化策略去理解,你就能知道答案。n8n28資訊網——每日最新資訊28at.com

回到 beginWork, 后續的邏輯會根據不同的 tag,創建不同類型的 Fiber 節點。n8n28資訊網——每日最新資訊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 跳過創建過程。n8n28資訊網——每日最新資訊28at.com

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

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

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

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

而不是沿用 didReceiveUpdate 的結果。n8n28資訊網——每日最新資訊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 方法。n8n28資訊網——每日最新資訊28at.com

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

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

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

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

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

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

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

四、遍歷順序

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

例如有這樣一個結構的節點。n8n28資訊網——每日最新資訊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 節點的鏈表深度遍歷執行。n8n28資訊網——每日最新資訊28at.com

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

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

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

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

五、總結

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

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

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

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

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

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

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

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

標簽:
  • 熱門焦點
  • K60 Pro官方停產 第三方瞬間漲價

    雖然沒有官方宣布,但Redmi的一些高管也已經透露了,Redmi K60 Pro已經停產且不會補貨,這一切都是為了即將到來的K60 Ultra鋪路,屬于廠家的正常操作。但有意思的是該機在停產之后
  • 微軟邀請 Microsoft 365 商業用戶,測試視頻編輯器 Clipchamp

    8 月 1 日消息,微軟近日宣布即將面向 Microsoft 365 商業用戶,開放 Clipchamp 應用,邀請用戶通過該應用來編輯視頻。微軟于 2021 年收購 Clipchamp,隨后開始逐步整合到 Microsof
  • 慕巖炮轟抖音,百合網今何在?

    來源:價值研究所 作者:Hernanderz&ldquo;難道就因為自己的一個產品牛逼了,從客服到總裁,都不愿意正視自己產品和運營上的問題,選擇逃避了嗎?&rdquo;這一番話,出自百合網聯合創
  • 消費結構調整丨巨頭低價博弈,拼多多還卷得動嗎?

    來源:征探財經作者:陳香羽隨著流量紅利的退潮,電商的存量博弈越來越明顯。曾經主攻中高端與品質的淘寶天貓、京東重拾&ldquo;低價&rdquo;口號。而過去與他們錯位競爭的拼多多,靠
  • 花7萬退貨退款無門:誰在縱容淘寶珠寶商家造假?

    來源:極點商業作者:楊銘在淘寶購買珠寶玉石后,因為保證金不夠賠付,店鋪關閉,退貨退款難、維權無門的比比皆是。&ldquo;提供相關產品鑒定證書,支持全國復檢,可以30天無理由退換貨。&
  • 品牌洞察丨服務本地,美團直播成效幾何?

    來源:17PR7月11日,美團App首頁推薦位出現&ldquo;美團直播&rdquo;的固定入口。在直播聚合頁面,外賣&ldquo;神槍手&rdquo;直播間、美團旅行直播間、美團買菜直播間等均已上線,同時
  • 阿里大調整

    來源:產品劉有媒體報道稱,近期淘寶天貓集團啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的&ldquo;征求意見版&rdquo;:1、取消P序列
  • 2022爆款:ROG魔霸6 冰川散熱系統持續護航

    喜逢開學季,各大商家開始推出自己的新產品,進行打折促銷活動。對于忠實的端游愛好者來說,能夠擁有一款夢寐以求的筆記本電腦是一件十分開心的事。但是現在的
  • 外交部:美方應停止在網絡安全問題上不負責任地指責他國

      中國外交部今天(16日)舉行例行記者會。會上,有記者問,美國情報官員稱,他們正在阻攔來自中國以及其他國家的黑客獲取相關科研成果。 中方對此有何評論?對此
Top 主站蜘蛛池模板: 永和县| 琼结县| 长岭县| 改则县| 钟山县| 罗源县| 鹤岗市| 刚察县| 福安市| 乌兰察布市| 长海县| 麻江县| 万载县| 旬邑县| 尚义县| 原平市| 五河县| 永川市| 天全县| 都安| 锡林浩特市| 含山县| 石阡县| 阿坝县| 深圳市| 宁津县| 宁明县| 池州市| 巴林左旗| 灵丘县| 渭源县| 玉溪市| 阳谷县| 曲沃县| 肇庆市| 赤城县| 兴山县| 射洪县| 余江县| 德格县| 密云县|