最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React Fiber與調(diào)和深入分析

 更新時(shí)間:2022年11月17日 08:27:53   作者:xiaofeng123aazz  
Fiber可以理解為一個(gè)執(zhí)行單元,每次執(zhí)行完一個(gè)執(zhí)行單元,React Fiber就會(huì)檢查還剩多少時(shí)間,如果沒(méi)有時(shí)間則將控制權(quán)讓出去,然后由瀏覽器執(zhí)行渲染操作,這篇文章主要介紹了React Fiber架構(gòu)原理剖析,需要的朋友可以參考下

一 引沿

Fiber 架構(gòu)是React16中引入的新概念,目的就是解決大型 React 應(yīng)用卡頓,React在遍歷更新每一個(gè)節(jié)點(diǎn)的時(shí)候都不是用的真實(shí)DOM,都是采用虛擬DOM,所以可以理解成fiber就是React的虛擬DOM,更新Fiber的過(guò)程叫做調(diào)和,每一個(gè)fiber都可以作為一個(gè)執(zhí)行單元來(lái)處理,所以每一個(gè) fiber 可以根據(jù)自身的過(guò)期時(shí)間expirationTime,來(lái)判斷是否還有空間時(shí)間執(zhí)行更新,如果沒(méi)有時(shí)間更新,就要把主動(dòng)權(quán)交給瀏覽器去渲染,做一些動(dòng)畫,重排( reflow ),重繪 repaints 之類的事情,這樣就能給用戶感覺(jué)不是很卡。

二 什么是調(diào)和

調(diào)和是一種算法,就是React對(duì)比新老虛擬DOM的過(guò)程,以決定需要更新哪一部分。

三 什么是Filber

Fiber的目的是為了讓React充分利用調(diào)度,以便做到如下幾點(diǎn):

  • 暫停工作,稍后再回來(lái)
  • 優(yōu)先考慮不同類型的工作
  • 重用以前完成的工作
  • 如果不再需要,則中止工作

為了實(shí)現(xiàn)上面的要求,我們需要把任務(wù)拆分成一個(gè)個(gè)可執(zhí)行的單元,這些可執(zhí)行的單元就叫做一個(gè)Fiber,一個(gè)Fiber就代表一個(gè)可執(zhí)行的單元。

一個(gè)Fiber就是一個(gè)普通的JS對(duì)象,包含一些組件的相關(guān)信息。

function FiberNode(){
  this.tag = tag;                  // fiber 標(biāo)簽 證明是什么類型fiber。
  this.key = key;                  // key調(diào)和子節(jié)點(diǎn)時(shí)候用到。 
  this.type = null;                // dom元素是對(duì)應(yīng)的元素類型,比如div,組件指向組件對(duì)應(yīng)的類或者函數(shù)。  
  this.stateNode = null;           // 指向?qū)?yīng)的真實(shí)dom元素,類組件指向組件實(shí)例,可以被ref獲取。
  this.return = null;              // 指向父級(jí)fiber
  this.child = null;               // 指向子級(jí)fiber
  this.sibling = null;             // 指向兄弟fiber 
  this.index = 0;                  // 索引
  this.ref = null;                 // ref指向,ref函數(shù),或者ref對(duì)象。
  this.pendingProps = pendingProps;// 在一次更新中,代表element創(chuàng)建
  this.memoizedProps = null;       // 記錄上一次更新完畢后的props
  this.updateQueue = null;         // 類組件存放setState更新隊(duì)列,函數(shù)組件存放
  this.memoizedState = null;       // 類組件保存state信息,函數(shù)組件保存hooks信息,dom元素為null
  this.dependencies = null;        // context或是時(shí)間的依賴項(xiàng)
  this.mode = mode;                //描述fiber樹(shù)的模式,比如 ConcurrentMode 模式
  this.effectTag = NoEffect;       // effect標(biāo)簽,用于收集effectList
  this.nextEffect = null;          // 指向下一個(gè)effect
  this.firstEffect = null;         // 第一個(gè)effect
  this.lastEffect = null;          // 最后一個(gè)effect
  this.expirationTime = NoWork;    // 通過(guò)不同過(guò)期時(shí)間,判斷任務(wù)是否過(guò)期, 在v17版本用lane表示。
  this.alternate = null;           //雙緩存樹(shù),指向緩存的fiber。更新階段,兩顆樹(shù)互相交替。
}

type 就是react的元素類型

export const FunctionComponent = 0;       // 對(duì)應(yīng)函數(shù)組件
export const ClassComponent = 1;          // 對(duì)應(yīng)的類組件
export const IndeterminateComponent = 2;  // 初始化的時(shí)候不知道是函數(shù)組件還是類組件 
export const HostRoot = 3;                // Root Fiber 可以理解為跟元素 , 通過(guò)reactDom.render()產(chǎn)生的根元素
export const HostPortal = 4;              // 對(duì)應(yīng)  ReactDOM.createPortal 產(chǎn)生的 Portal 
export const HostComponent = 5;           // dom 元素 比如 <div>
export const HostText = 6;                // 文本節(jié)點(diǎn)
export const Fragment = 7;                // 對(duì)應(yīng) <React.Fragment> 
export const Mode = 8;                    // 對(duì)應(yīng) <React.StrictMode>   
export const ContextConsumer = 9;         // 對(duì)應(yīng) <Context.Consumer>
export const ContextProvider = 10;        // 對(duì)應(yīng) <Context.Provider>
export const ForwardRef = 11;             // 對(duì)應(yīng) React.ForwardRef
export const Profiler = 12;               // 對(duì)應(yīng) <Profiler/ >
export const SuspenseComponent = 13;      // 對(duì)應(yīng) <Suspense>
export const MemoComponent = 14;          // 對(duì)應(yīng) React.memo 返回的組件

比如元素結(jié)構(gòu)如下:

export default class Parent extends React.Component{
   render(){
     return <div>
       <h1>hello,world</h1>
       <Child />
     </div>
   }
}
function Child() {
  return <p>child</p>
}

對(duì)應(yīng)的Filber結(jié)構(gòu)如下:

有了上面的概念后我們就自己實(shí)現(xiàn)一個(gè)Fiber的更新機(jī)制

四 實(shí)現(xiàn)調(diào)和的過(guò)程

我們通過(guò)渲染一段jsx來(lái)說(shuō)明React的調(diào)和過(guò)程,也就是我們要手寫實(shí)現(xiàn)ReactDOM.render()

const jsx = (
  <div className="border">
    <h1>hello</h1>
    <a  rel="external nofollow" >React</a>
  </div>
)
ReactDOM.render(
  jsx,
  document.getElementById('root')
);

1. 創(chuàng)建FiberRoot

react-dom.js

function createFiberRoot(element, container){
    return {
    type: container.nodeName.toLocaleLowerCase(),
    props: { children: element },
    stateNode: container
  }
}
function render(element, container) {
  const FibreRoot = createFiberRoot(element, container)
  scheduleUpdateOnFiber(FibreRoot)
}
export default { render }

參考React實(shí)戰(zhàn)視頻講解:進(jìn)入學(xué)習(xí)

2. render階段

調(diào)和的核心是render和commit,本文不講調(diào)度過(guò)程,我們會(huì)簡(jiǎn)單的用requestIdleCallback代替React的調(diào)度過(guò)程。

ReactFiberWorkloop.js

let wipRoot = null // work in progress
let nextUnitOfwork = null // 下一個(gè)fiber節(jié)點(diǎn)
export function scheduleUpdateOnFiber(fiber) {
  wipRoot = fiber
  nextUnitOfwork = fiber
}
function workLoop(IdleDeadline) {
  while(nextUnitOfwork && IdleDeadline.timeRemaining() > 0) {
    nextUnitOfwork = performUnitOfWork(nextUnitOfwork)
  }
}
function performUnitOfWork() {}
requestIdleCallback(workLoop)

每一個(gè) fiber 可以看作一個(gè)執(zhí)行的單元,在調(diào)和過(guò)程中,每一個(gè)發(fā)生更新的 fiber 都會(huì)作為一次 workInProgress 。那么 workLoop 就是執(zhí)行每一個(gè)單元的調(diào)度器,如果渲染沒(méi)有被中斷,那么 workLoop 會(huì)遍歷一遍 fiber 樹(shù)

performUnitOfWork 包括兩個(gè)階段:

  • 是向下調(diào)和的過(guò)程,就是由 fiberRoot 按照 child 指針逐層向下調(diào)和,期間會(huì)執(zhí)行函數(shù)組件,實(shí)例類組件,diff 調(diào)和子節(jié)點(diǎn)
  • 是向上歸并的過(guò)程,如果有兄弟節(jié)點(diǎn),會(huì)返回 sibling兄弟,沒(méi)有返回 return 父級(jí),一直返回到 fiebrRoot

這么一上一下,構(gòu)成了整個(gè) fiber 樹(shù)的調(diào)和。

import { updateHostComponent } from './ReactFiberReconciler'
function performUnitOfWork(wip) {
  // 1. 更新wip
  const { type } = wip
  if (isStr(type)) {
    // type是string,更新普通元素節(jié)點(diǎn)
    updateHostComponent(wip)
  } else if (isFn(type)) {
    // ...
  }
  // 2. 返回下一個(gè)要更新的任務(wù) 深度優(yōu)先遍歷
  if (wip.child) {
    return wip.child
  }
  let next = wip
  while(next) {
    if (next.sibling) {
      return next.sibling
    }
    next = next.return
  }
  return null
}

根據(jù)type類型區(qū)分是FunctionComponent/ClassComponent/HostComponent/…

本文中只處理HostComponent類型,其他類型的處理可以看文末的完整代碼鏈接。

ReactFiberReconciler.js

import { createFiber } from './createFiber'
export function updateHostComponent(wip) {
  if (!wip.stateNode) {
    wip.stateNode = document.createElement(wip.type);
    updateNode(wip.stateNode, wip.props);
  }
  // 調(diào)和子節(jié)點(diǎn)
  reconcileChildren(wip, wip.props.children);
}
function reconcileChildren(returnFiber, children) {
  if (isStr(children)) {
    return
  }
  const newChildren = isArray(children) ? children : [children];
  let previousNewFiber = null
  for(let i = 0; i < newChildren.length; i++) {
    const newChild = newChildren[i];
    const newFiber = createFiber(newChild, returnFiber)
    if (previousNewFiber === null) {
      returnFiber.child = newFiber
    } else {
      previousNewFiber.sibling = newFiber
    }
    previousNewFiber = newFiber
  }
}
function updateNode(node, nextVal) {
  Object.keys(nextVal).forEach((k) => {
    if (k === "children") {
      if (isStringOrNumber(nextVal[k])) {
        node.textContent = nextVal[k];
      }
    } else {
      node[k] = nextVal[k];
    }
  });
}

createFiber.js

export function createFiber(vnode, returnFiber) {
  const newFiber = {
    type: vnode.type,   // 標(biāo)記節(jié)點(diǎn)類型
    key: vnode.key,     // 標(biāo)記節(jié)點(diǎn)在當(dāng)前層級(jí)下的唯一性
    props: vnode.props, // 屬性
    stateNode: null,    // 如果組件是原生標(biāo)簽則是dom節(jié)點(diǎn),如果是類組件則是類實(shí)例
    child: null,        // 第一個(gè)子節(jié)點(diǎn)
    return: returnFiber,// 父節(jié)點(diǎn)
    sibling: null,      // 下一個(gè)兄弟節(jié)點(diǎn)
  };
  return newFiber;
}

至此已經(jīng)完成了render階段,下面是commit階段,commit階段就是依據(jù)Fiber結(jié)構(gòu)操作DOM

function workLoop(IdleDeadline) {
  while(nextUnitOfwork && IdleDeadline.timeRemaining() > 0) {
    nextUnitOfwork = performUnitOfWork(nextUnitOfwork)
  }
  // commit
  if (!nextUnitOfwork && wipRoot) {
    commitRoot();
  }
}
function commitRoot() {
  commitWorker(wipRoot.child)
  wipRoot = null;
}
function commitWorker(wip) {
  if (!wip) {
    return
  }
  // 1. 提交自己
  const { stateNode } = wip
  let parentNode = wip.return.stateNode
  if (stateNode) {
    parentNode.appendChild(stateNode);
  }
  // 2. 提交子節(jié)點(diǎn)
  commitWorker(wip.child);
  // 3. 提交兄弟節(jié)點(diǎn)
  commitWorker(wip.sibling);
}

五 總結(jié)

  • Fiber結(jié)構(gòu),F(xiàn)iber的生成過(guò)程。
  • 調(diào)和過(guò)程,以及 render 和 commit 兩大階段。

到此這篇關(guān)于React Fiber與調(diào)和深入分析的文章就介紹到這了,更多相關(guān)React Fiber與調(diào)和內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入理解React中何時(shí)使用箭頭函數(shù)

    深入理解React中何時(shí)使用箭頭函數(shù)

    對(duì)于剛學(xué)前端的大家來(lái)說(shuō),對(duì)于React中的事件監(jiān)聽(tīng)寫法有所疑問(wèn)很正常,特別是React中箭頭函數(shù)使用這塊,下面這篇文章主要給大家深入的講解了關(guān)于React中何時(shí)使用箭頭函數(shù)的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • React 組件間的通信示例

    React 組件間的通信示例

    這篇文章主要介紹了React 組件間的通信示例,主要通信劃分為三種,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • React中使用antd組件的方法

    React中使用antd組件的方法

    antd?是基于?Ant?Design?設(shè)計(jì)體系的?React?UI?組件庫(kù),主要用于研發(fā)企業(yè)級(jí)中后臺(tái)產(chǎn)品,這篇文章主要介紹了React中使用antd組件,需要的朋友可以參考下
    2022-09-09
  • react+antd 遞歸實(shí)現(xiàn)樹(shù)狀目錄操作

    react+antd 遞歸實(shí)現(xiàn)樹(shù)狀目錄操作

    這篇文章主要介紹了react+antd 遞歸實(shí)現(xiàn)樹(shù)狀目錄操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • 引入代碼檢查工具stylelint實(shí)戰(zhàn)問(wèn)題經(jīng)驗(yàn)總結(jié)分享

    引入代碼檢查工具stylelint實(shí)戰(zhàn)問(wèn)題經(jīng)驗(yàn)總結(jié)分享

    eslint的配置引入比較簡(jiǎn)單,網(wǎng)上有比較多的教程,而stylelint的教程大多語(yǔ)焉不詳。在這里,我會(huì)介紹一下我在引入stylelint所遇到的坑,以及解決方法
    2021-11-11
  • 淺談箭頭函數(shù)寫法在ReactJs中的使用

    淺談箭頭函數(shù)寫法在ReactJs中的使用

    這篇文章主要介紹了淺談箭頭函數(shù)寫法在ReactJs中的使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • hooks寫React組件的5個(gè)注意細(xì)節(jié)詳解

    hooks寫React組件的5個(gè)注意細(xì)節(jié)詳解

    這篇文章主要為大家介紹了hooks寫React組件的5個(gè)需要注意的細(xì)節(jié)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 淺談react受控組件與非受控組件(小結(jié))

    淺談react受控組件與非受控組件(小結(jié))

    本篇文章主要介紹了淺談react受控組件與非受控組件(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • react將文件轉(zhuǎn)為base64上傳的示例代碼

    react將文件轉(zhuǎn)為base64上傳的示例代碼

    本文主要介紹了react將文件轉(zhuǎn)為base64上傳的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • React報(bào)錯(cuò)之Parameter event implicitly has an any type解決

    React報(bào)錯(cuò)之Parameter event implicitly has a

    這篇文章主要為大家介紹了React報(bào)錯(cuò)之Parameter event implicitly has an any type,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論

巍山| 石家庄市| 墨玉县| 宾川县| 资源县| 嘉义县| 曲周县| 芒康县| 射洪县| 韶山市| 天峨县| 潼关县| 唐河县| 新宁县| 青海省| 岱山县| 萨嘎县| 斗六市| 樟树市| 富源县| 太仓市| 楚雄市| 葫芦岛市| 达孜县| 乐清市| 平安县| 尚志市| 江津市| 图片| 邹平县| 义乌市| 怀化市| 城市| 嵊州市| 保山市| 南投县| 天镇县| 永城市| 米易县| 康定县| 昌宁县|