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

React?Fiber構(gòu)建源碼解析

 更新時(shí)間:2023年02月06日 10:49:19   作者:GW_劉振  
這篇文章主要為大家介紹了React?Fiber構(gòu)建源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

前面的章節(jié),我們?cè)趓ender方法里,簡(jiǎn)單涉及到了fiber,那么:

  • fiber究竟是什么?
  • fiber的出現(xiàn)解決了什么問題?
  • 為什么fiber之前的版本,沒辦法解決

下面,我們帶著這些問題,來(lái)仔細(xì)聊聊Fiber

一. Fiber是什么

在fiber出現(xiàn)之前,react的架構(gòu)體系只有協(xié)調(diào)器reconciler和渲染器render。

當(dāng)前有新的update時(shí),react會(huì)遞歸所有的vdom節(jié)點(diǎn),如果dom節(jié)點(diǎn)過多,會(huì)導(dǎo)致其他事件影響滯后,造成卡頓。即之前的react版本無(wú)法中斷工作過程,一旦遞歸開始無(wú)法停留下來(lái)。

為了解決這一系列問題,react歷時(shí)多年重構(gòu)了底層架構(gòu),引入了fiber。 fiber的出現(xiàn)使得react能夠異步可中斷工作任務(wù),并且可以在瀏覽器空閑時(shí),從中斷處繼續(xù)往下工作。 當(dāng)出現(xiàn)多個(gè)高優(yōu)先任務(wù)并行時(shí),react引入lane模型取代之前的expireTime機(jī)制。

這里提及下vue工作原理,為什么有新的update任務(wù)時(shí),vue不需要做全量遞歸,而react需要?(留個(gè)懸念,大家可以先思考下)

fiber本質(zhì)上是一種數(shù)據(jù)結(jié)構(gòu),在react17后,沒有vdom概念,一切皆是Fiber,但Fiber != vdom。

二. FiberRoot

FiberRoot是react啟動(dòng)階段,要構(gòu)建的fiber對(duì)象。與之容易混淆是rootFiber,下面會(huì)具體介紹。

fiberRoot生成

  function createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) {
    var root = new FiberRootNode(containerInfo, tag, hydrate);
    // stateNode is any.
    var uninitializedFiber = createHostRootFiber(tag);
    root.current = uninitializedFiber;
    uninitializedFiber.stateNode = root;
    initializeUpdateQueue(uninitializedFiber);
    return root;
  }

fiberRoot類

function FiberRootNode(containerInfo, tag, hydrate) {
    this.tag = tag;
    this.containerInfo = containerInfo;
    this.pendingChildren = null;
    this.current = null;
    this.pingCache = null;
    this.finishedWork = null;
    this.timeoutHandle = noTimeout;
    this.context = null;
    this.pendingContext = null;
    this.hydrate = hydrate;
    this.callbackNode = null;
    this.callbackPriority = NoLanePriority;
    this.eventTimes = createLaneMap(NoLanes);
    this.expirationTimes = createLaneMap(NoTimestamp);
    this.pendingLanes = NoLanes;
    this.suspendedLanes = NoLanes;
    this.pingedLanes = NoLanes;
    this.expiredLanes = NoLanes;
    this.mutableReadLanes = NoLanes;
    this.finishedLanes = NoLanes;
    this.entangledLanes = NoLanes;
    this.entanglements = createLaneMap(NoLanes);
    {
      this.mutableSourceEagerHydrationData = null;
    }
    {
      this.interactionThreadID = unstable_getThreadID();
      this.memoizedInteractions = new Set();
      this.pendingInteractionMap = new Map();
    }
    {
      switch (tag) {
        case BlockingRoot:
          this._debugRootType = 'createBlockingRoot()';
          break;
        case ConcurrentRoot:
          this._debugRootType = 'createRoot()';
          break;
        case LegacyRoot:
          this._debugRootType = 'createLegacyRoot()';
          break;
      }
    }
  }

fiberRoot本質(zhì)上fiber的頂層對(duì)象,其中tag記錄了幾種啟動(dòng)模式:

  • 0普通模式
  • 1 小部分并發(fā)模式
  • 2 并發(fā)模式

啟動(dòng)模式的不同,在后協(xié)調(diào)階段有具體差異。

該類引用的實(shí)例,即current對(duì)象是rootFiber。finishedWork是fiber完成協(xié)調(diào)器work之后的結(jié)果,下面有許多字段都帶有l(wèi)ane,這里可以先不關(guān)注,后面章節(jié)我們單獨(dú)聊聊Lane模型

三. RootFiber

rootFiber生成

  function createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) {
    var root = new FiberRootNode(containerInfo, tag, hydrate);
    // stateNode is any.
    var uninitializedFiber = createHostRootFiber(tag);
    root.current = uninitializedFiber;
    uninitializedFiber.stateNode = root;
    initializeUpdateQueue(uninitializedFiber);
    return root;
  }

createHostRootFiber

  function createHostRootFiber(tag) {
    var mode;
    if (tag === ConcurrentRoot) {
      mode = ConcurrentMode | BlockingMode | StrictMode;
    } else if (tag === BlockingRoot) {
      mode = BlockingMode | StrictMode;
    } else {
      mode = NoMode;
    }
    if ( isDevToolsPresent) {
      // Always collect profile timings when DevTools are present.
      // This enables DevTools to start capturing timing at any point–
      // Without some nodes in the tree having empty base times.
      mode |= ProfileMode;
    }
    return createFiber(HostRoot, null, null, mode);
  }

FiberNode

function FiberNode(tag, pendingProps, key, mode) {
    this.tag = tag;
    this.key = key;
    this.elementType = null;
    this.type = null;
    this.stateNode = null;
    this.return = null;
    this.child = null;
    this.sibling = null;
    this.index = 0;
    this.ref = null;
    this.pendingProps = pendingProps; 
    this.memoizedProps = null; 
    this.updateQueue = null; 
    this.memoizedState = null;  
    this.dependencies = null;
    this.mode = mode; // Effects
    this.flags = NoFlags;     
    this.nextEffect = null;  
    this.firstEffect = null; 
    this.lastEffect = null; 
    this.lanes = NoLanes;
    this.childLanes = NoLanes;
    this.alternate = null;
    {
      this.actualDuration = Number.NaN;
      this.actualStartTime = Number.NaN;
      this.selfBaseDuration = Number.NaN;
      this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization.
      this.actualDuration = 0;
      this.actualStartTime = -1;
      this.selfBaseDuration = 0;
      this.treeBaseDuration = 0;
    }
    {
      // This isn't directly used but is handy for debugging internals:
      this._debugID = debugCounter++;
      this._debugSource = null;
      this._debugOwner = null;
      this._debugNeedsRemount = false;
      this._debugHookTypes = null;
      if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
        Object.preventExtensions(this);
      }
    }
  }

到這里,fiberNode是一個(gè)類,往下的所有dom都將實(shí)例化這個(gè)類。

這里的tag依舊是啟動(dòng)模式,return是父節(jié)點(diǎn)fiber,child是子節(jié)點(diǎn)第一個(gè)fiber,sibling是兄弟節(jié)點(diǎn)的fiber。

另外,flags很重要,在后續(xù)work階段會(huì)大量使用,另外flags和lane都是二進(jìn)制數(shù)據(jù)對(duì)象,后面大量運(yùn)用位運(yùn)算。

effect對(duì)象,會(huì)在work loop階段生成,也就是副作用,比如我們寫的useEffect,都在work lopp階段被掛載。

每個(gè)fiber的stateNode指向具體實(shí)例節(jié)點(diǎn)。

flags

export type Flags = number;
export const NoFlags = /*                      */ 0b000000000000000000;
export const PerformedWork = /*                */ 0b000000000000000001;
export const Placement = /*                    */ 0b000000000000000010;
export const Update = /*                       */ 0b000000000000000100;
export const PlacementAndUpdate = /*           */ 0b000000000000000110;
export const Deletion = /*                     */ 0b000000000000001000;
export const ContentReset = /*                 */ 0b000000000000010000;
export const Callback = /*                     */ 0b000000000000100000;
export const DidCapture = /*                   */ 0b000000000001000000;
export const Ref = /*                          */ 0b000000000010000000;
export const Snapshot = /*                     */ 0b000000000100000000;
export const Passive = /*                      */ 0b000000001000000000;
// TODO (effects) Remove this bit once the new reconciler is synced to the old.
export const PassiveUnmountPendingDev = /*     */ 0b000010000000000000;
export const Hydrating = /*                    */ 0b000000010000000000;
export const HydratingAndUpdate = /*           */ 0b000000010000000100;
// Passive & Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /*          */ 0b000000001110100100;
// Union of all host effects
export const HostEffectMask = /*               */ 0b000000011111111111;
// These are not really side effects, but we still reuse this field.
export const Incomplete = /*                   */ 0b000000100000000000;
export const ShouldCapture = /*                */ 0b000001000000000000;
export const ForceUpdateForLegacySuspense = /* */ 0b000100000000000000;
export const PassiveStatic = /*                */ 0b001000000000000000;
export const BeforeMutationMask = /*           */ 0b000000001100001010;
export const MutationMask = /*                 */ 0b000000010010011110;
export const LayoutMask = /*                   */ 0b000000000010100100;
export const PassiveMask = /*                  */ 0b000000001000001000;
export const StaticMask = /*                   */ 0b001000000000000000;
export const MountLayoutDev = /*               */ 0b010000000000000000;
export const MountPassiveDev = /*              */ 0b100000000000000000;

lane

export const NoLanes: Lanes = /*                        */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /*                          */ 0b0000000000000000000000000000000;
export const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /*                 */ 0b0000000000000000000000000000010;
export const InputDiscreteHydrationLane: Lane = /*      */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /*                    */ 0b0000000000000000000000000011000;
const InputContinuousHydrationLane: Lane = /*           */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /*                  */ 0b0000000000000000000000011000000;
export const DefaultHydrationLane: Lane = /*            */ 0b0000000000000000000000100000000;
export const DefaultLanes: Lanes = /*                   */ 0b0000000000000000000111000000000;
const TransitionHydrationLane: Lane = /*                */ 0b0000000000000000001000000000000;
const TransitionLanes: Lanes = /*                       */ 0b0000000001111111110000000000000;
const RetryLanes: Lanes = /*                            */ 0b0000011110000000000000000000000;
export const SomeRetryLane: Lanes = /*                  */ 0b0000010000000000000000000000000;
export const SelectiveHydrationLane: Lane = /*          */ 0b0000100000000000000000000000000;
const NonIdleLanes = /*                                 */ 0b0000111111111111111111111111111;
export const IdleHydrationLane: Lane = /*               */ 0b0001000000000000000000000000000;
const IdleLanes: Lanes = /*                             */ 0b0110000000000000000000000000000;
export const OffscreenLane: Lane = /*                   */ 0b1000000000000000000000000000000;

關(guān)于flags和lane,我們先有個(gè)感性認(rèn)知,后面章節(jié)單獨(dú)分析

initializeUpdateQueue

  function initializeUpdateQueue(fiber) {
    var queue = {
      baseState: fiber.memoizedState,
      firstBaseUpdate: null,
      lastBaseUpdate: null,
      shared: {
        pending: null
      },
      effects: null
    };
    fiber.updateQueue = queue;
  }

rootFiber上調(diào)用initializeUpdateQueue,初始化queue對(duì)象,這里僅僅是初始化對(duì)象而已,并不是許多文章說(shuō)fiber加入更新隊(duì)列。fiber的更新隊(duì)列和這里沒有任何關(guān)系,fiber的更新隊(duì)列是后續(xù)schedule調(diào)度的task queue。

四. Root

root對(duì)象是legacyCreateRootFromDOMContainer方法的返回對(duì)象,這個(gè)對(duì)象是全局唯一,并貫穿了react后續(xù)的各階段計(jì)算。

至此,我們對(duì)應(yīng)fiber有個(gè)感性的認(rèn)知。另外需要說(shuō)明的是,每個(gè)dom節(jié)點(diǎn)都是fiber,fiber通過return, child, sibling關(guān)聯(lián)其他fiber,本質(zhì)上fiber是個(gè)鏈表數(shù)據(jù)結(jié)構(gòu),這一點(diǎn)和后續(xù)的effect數(shù)據(jù)結(jié)構(gòu)還是有區(qū)別的。

在root生成后,首次初始化應(yīng)用,將進(jìn)入核心updateContainer方法

updateContainer(children, fiberRoot, parentComponent, callback);

updateContainer

  function updateContainer(element, container, parentComponent, callback) {
      // ...省略eventTime和lane相關(guān),后續(xù)單獨(dú)介紹
    var update = createUpdate(eventTime, lane); // Caution: React DevTools currently depends on this property
    // being called "element".
    update.payload = {
      element: element
    };
    callback = callback === undefined ? null : callback;
    if (callback !== null) {
      {
        if (typeof callback !== 'function') {
          error('render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback);
        }
      }
      update.callback = callback;
    }
    enqueueUpdate(current$1, update);
    scheduleUpdateOnFiber(current$1, lane, eventTime);
    return lane;
  }

createUpdate

  function createUpdate(eventTime, lane) {
    var update = {
      eventTime: eventTime,
      lane: lane,
      tag: UpdateState,
      payload: null,
      callback: null,
      next: null
    };
    return update;
  }
  function enqueueUpdate(fiber, update) {
    var updateQueue = fiber.updateQueue;
    if (updateQueue === null) {
      // Only occurs if the fiber has been unmounted.
      return;
    }
    var sharedQueue = updateQueue.shared;
    var pending = sharedQueue.pending;
    if (pending === null) {
      // This is the first update. Create a circular list.
      update.next = update;
    } else {
      update.next = pending.next;
      pending.next = update;
    }
    sharedQueue.pending = update;
  }

在rootFiber上,創(chuàng)建更新對(duì)象,并掛載至enqueueUpdate上。

update對(duì)象上payload很重要,后面在協(xié)調(diào)階段-fiber樹構(gòu)建階段是重要的輸入。

update對(duì)象也是鏈表結(jié)構(gòu),通過next關(guān)聯(lián)下一個(gè)update對(duì)象。

至此,fiber的初始化對(duì)象到這里就結(jié)束了,目前內(nèi)存中只存在fiberRoot和rootFiber對(duì)象,下面調(diào)的scheduleUpdateOnFiber方法,將正式進(jìn)入?yún)f(xié)調(diào)階段,更多關(guān)于React構(gòu)建Fiber的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • react 下拉框內(nèi)容回顯的實(shí)現(xiàn)思路

    react 下拉框內(nèi)容回顯的實(shí)現(xiàn)思路

    這篇文章主要介紹了react 下拉框內(nèi)容回顯,實(shí)現(xiàn)思路是通過將下拉框選項(xiàng)的value和label一起存儲(chǔ)到state中, 初始化表單數(shù)據(jù)時(shí)將faqType對(duì)應(yīng)的label查找出來(lái)并設(shè)置到Form.Item中,最后修改useEffect,需要的朋友可以參考下
    2024-05-05
  • react配置webpack-bundle-analyzer項(xiàng)目?jī)?yōu)化踩坑記錄

    react配置webpack-bundle-analyzer項(xiàng)目?jī)?yōu)化踩坑記錄

    這篇文章主要介紹了react配置webpack-bundle-analyzer項(xiàng)目?jī)?yōu)化踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • React Native日期時(shí)間選擇組件的示例代碼

    React Native日期時(shí)間選擇組件的示例代碼

    本篇文章主要介紹了React Native日期時(shí)間選擇組件的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-04-04
  • React中memo useCallback useMemo方法作用及使用場(chǎng)景

    React中memo useCallback useMemo方法作用及使用場(chǎng)景

    這篇文章主要為大家介紹了React中三個(gè)hooks方法memo useCallback useMemo的作用及使用場(chǎng)景示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-03-03
  • React Native使用Modal自定義分享界面的示例代碼

    React Native使用Modal自定義分享界面的示例代碼

    本篇文章主要介紹了React Native使用Modal自定義分享界面的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • React實(shí)現(xiàn)類似淘寶tab居中切換效果的示例代碼

    React實(shí)現(xiàn)類似淘寶tab居中切換效果的示例代碼

    這篇文章主要介紹了React實(shí)現(xiàn)類似淘寶tab居中切換效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • React實(shí)現(xiàn)合成事件的源碼分析

    React實(shí)現(xiàn)合成事件的源碼分析

    React?中的事件,是對(duì)原生事件的封裝,叫做合成事件。抽象出一層合成事件,是為了做兼容,抹平不同瀏覽器之間的差異。本文將從事件綁定和事件觸發(fā)角度,帶大家解讀下源碼,感興趣的可以了解一下
    2022-12-12
  • React學(xué)習(xí)筆記之條件渲染(一)

    React學(xué)習(xí)筆記之條件渲染(一)

    條件渲染在React里就和js里的條件語(yǔ)句一樣。下面這篇文章主要給大家介紹了關(guān)于React學(xué)習(xí)記錄之條件渲染的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-07-07
  • React Router V4使用指南(精講)

    React Router V4使用指南(精講)

    這篇文章主要介紹了React Router V4使用指南(精講),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2018-09-09
  • react實(shí)現(xiàn)路由動(dòng)畫跳轉(zhuǎn)功能

    react實(shí)現(xiàn)路由動(dòng)畫跳轉(zhuǎn)功能

    這篇文章主要介紹了react路由動(dòng)畫跳轉(zhuǎn)功能,大概思路是下載第三方庫(kù)?引用,創(chuàng)建css文件引用,想要實(shí)現(xiàn)跳轉(zhuǎn)動(dòng)畫功能,就在那個(gè)組件的根節(jié)點(diǎn)綁定classname屬性即可,在跳轉(zhuǎn)的時(shí)候即可實(shí)現(xiàn),需要的朋友可以參考下
    2023-10-10

最新評(píng)論

稷山县| 犍为县| 西和县| 边坝县| 隆昌县| 新宁县| 安溪县| 开封县| 克东县| 轮台县| 基隆市| 沙田区| 玉树县| 邹城市| 佛山市| 宿迁市| 华亭县| 莱州市| 灌南县| 台东县| 汶川县| 葫芦岛市| 西青区| 井研县| 台安县| 申扎县| 德安县| 南投县| 栾川县| 石屏县| 福鼎市| 甘洛县| 宁晋县| 隆回县| 青海省| 新巴尔虎右旗| 龙江县| 来凤县| 天峨县| 平安县| 竹北市|