亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

React16.2的fiber架構(gòu)

lansheng228 / 1877人閱讀

摘要:司徒正美,加群一起研究與用于調(diào)整渲染順序,高優(yōu)先級(jí)的組件先執(zhí)行這只是一部分更新邏輯,簡(jiǎn)直沒完沒了,下次繼續(xù)添上流程圖,回憶一下本文學(xué)到的東西

React16真是一天一改,如果現(xiàn)在不看,以后也很難看懂了。

在React16中,雖然也是通過JSX編譯得到一個(gè)虛擬DOM對(duì)象,但對(duì)這些虛擬DOM對(duì)象的再加工則是經(jīng)過翻天覆地的變化。我們需要追根溯底,看它是怎么一步步轉(zhuǎn)換過來(lái)的。我們先不看什么組件render,先找到ReactDOM.render。在ReactDOM的源碼里,有三個(gè)類似的東西:

//by 司徒正美, 加群:370262116 一起研究React與anujs
// https://github.com/RubyLouvre/anu 歡迎加star

ReactDOM= {
 hydrate: function (element, container, callback) {
    //新API,代替render
    return renderSubtreeIntoContainer(null, element, container, true, callback);
  },
  render: function (element, container, callback) {
    //React15的重要API,逐漸退出舞臺(tái)
    return renderSubtreeIntoContainer(null, element, container, false, callback);
  },
  unstable_renderSubtreeIntoContainer: function (parentComponent, element, containerNode, callback) {
    //用于生成子樹,廢棄
    return renderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback);
  }
}

我們看renderSubtreeIntoContainer,這是一個(gè)內(nèi)部API

//by 司徒正美, 加群:370262116 一起研究React與anujs

function renderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {

  var root = container._reactRootContainer;
  if (!root) {
    //如果是第一次對(duì)這個(gè)元素進(jìn)行渲染,那么它會(huì)清空元素的內(nèi)部
    var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
    // First clear any existing content.
    if (!shouldHydrate) {
      var warned = false;
      var rootSibling = void 0;
      while (rootSibling = container.lastChild) {
        container.removeChild(rootSibling);
      }
    }

    var newRoot = DOMRenderer.createContainer(container, shouldHydrate);
    //創(chuàng)建一個(gè)HostRoot對(duì)象,是Fiber對(duì)象的一種
    root = container._reactRootContainer = newRoot;
    
    // Initial mount should not be batched.
    DOMRenderer.unbatchedUpdates(function () {
     //對(duì)newRoot對(duì)象進(jìn)行更新
      DOMRenderer.updateContainer(children, newRoot, parentComponent, callback);
    });
  } else {
    //對(duì)root對(duì)象進(jìn)行更新
    DOMRenderer.updateContainer(children, root, parentComponent, callback);
  }
  return DOMRenderer.getPublicRootInstance(root);
}

看一下DOMRenderer.createContainer是怎么創(chuàng)建root對(duì)象的。

首先DOMRenderer這個(gè)對(duì)象是由一個(gè)叫reactReconciler的方法生成,需要傳入一個(gè)對(duì)象,將一些東西注進(jìn)去。最后產(chǎn)生一個(gè)對(duì)象,里面就有createContainer這個(gè)方法

// containerInfo就是ReactDOM.render(
, containerInfo)的第二個(gè)對(duì)象,換言之是一個(gè)元素節(jié)點(diǎn) createContainer: function (containerInfo, hydrate) { return createFiberRoot(containerInfo, hydrate); },

再看createFiberRoot是怎么將一個(gè)真實(shí)DOM變成一個(gè)Fiber對(duì)象

//by 司徒正美, 加群:370262116 一起研究React與anujs

function createFiberRoot(containerInfo, hydrate) {
  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  var uninitializedFiber = createHostRootFiber();
  var root = {
    current: uninitializedFiber,
    containerInfo: containerInfo,
    pendingChildren: null,
    remainingExpirationTime: NoWork,
    isReadyForCommit: false,
    finishedWork: null,
    context: null,
    pendingContext: null,
    hydrate: hydrate,
    nextScheduledRoot: null
  };
  uninitializedFiber.stateNode = root;

  return root;
}

function createHostRootFiber() {
  var fiber = createFiber(HostRoot, null, NoContext);
  return fiber;
}

var createFiber = function (tag, key, internalContextTag) {
  return new FiberNode(tag, key, internalContextTag);
};


function FiberNode(tag, key, internalContextTag) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this["return"] = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  this.ref = null;

  this.pendingProps = null;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;

  this.internalContextTag = internalContextTag;

  // Effects
  this.effectTag = NoEffect;
  this.nextEffect = null;

  this.firstEffect = null;
  this.lastEffect = null;

  this.expirationTime = NoWork;

  this.alternate = null;


}

所有Fiber對(duì)象都是FiberNode的實(shí)例,它有許多種類型,通過tag來(lái)標(biāo)識(shí)。

內(nèi)部有許多方法來(lái)生成Fiber對(duì)象

createFiberFromElement (type為類,無(wú)狀態(tài)函數(shù),元素標(biāo)簽名)

createFiberFromFragment (type為React.Fragment)

createFiberFromText (在JSX中表現(xiàn)為字符串,數(shù)字)

createFiberFromHostInstanceForDeletion

createFiberFromCall

createFiberFromReturn

createFiberFromPortal (createPortal就會(huì)產(chǎn)生該類型)

createFiberRoot (用于ReactDOM.render的根節(jié)點(diǎn))

createFiberRoot就是創(chuàng)建了一個(gè)普通對(duì)象,里面有一個(gè)current屬性引用fiber對(duì)象,有一個(gè)containerInfo屬性引用剛才的DOM節(jié)點(diǎn),然后fiber對(duì)象有一個(gè)stateNode引用剛才的普通對(duì)象。在React15中,stateNode應(yīng)該是一個(gè)組件實(shí)例或真實(shí)DOM,可能單純是為了對(duì)齊,就創(chuàng)建一個(gè)普通對(duì)象。 最后返回普通對(duì)象。

我們先不看 DOMRenderer.unbatchedUpdates,直接看DOMRenderer.updateContainer。

//children就是ReactDOM的第一個(gè)參數(shù),children通常表示一個(gè)數(shù)組,但是現(xiàn)在它泛指各種虛擬DOM了,第二個(gè)對(duì)象就是剛才提到的普通對(duì)象,我們可以稱它為根組件,parentComponent為之前的根組件,現(xiàn)在它為null
 DOMRenderer.updateContainer(children, newRoot, parentComponent, callback);

updateContainer的源碼也很簡(jiǎn)單,就是獲得上下文對(duì)象,決定它是叫context還是pendingContext,最后丟給scheduleTopLevelUpdate

//by 司徒正美, 加群:370262116 一起研究React與anujs

 updateContainer: function (element, container, parentComponent, callback) {
      var current = container.current;//createFiberRoot中創(chuàng)建的fiber對(duì)象
      var context = getContextForSubtree(parentComponent);
      if (container.context === null) {
        container.context = context;
      } else {
        container.pendingContext = context;
      }
      // 原傳名為 children, newRoot, parentComponent, callback
      // newRoot.fiber, children, callback
      scheduleTopLevelUpdate(current, element, callback);
    },

getContextForSubtree的實(shí)現(xiàn)

//by 司徒正美, 加群:370262116 一起研究React與anujs

function getContextForSubtree(parentComponent) {
  if (!parentComponent) {
    return emptyObject_1;
  }

  var fiber = get(parentComponent);
  var parentContext = findCurrentUnmaskedContext(fiber);
  return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext;
}
//isContextConsumer與isContextProvider是兩個(gè)全新的概念,
// 從原上下文中抽取一部分出來(lái)
function isContextConsumer(fiber) {
  return fiber.tag === ClassComponent && fiber.type.contextTypes != null;
}
//isContextProvider,產(chǎn)生一個(gè)新的上下文
function isContextProvider(fiber) {
  return fiber.tag === ClassComponent && fiber.type.childContextTypes != null;
}

function _processChildContext(currentContext) {
    var Component = this._currentElement.type;
    var inst = this._instance;
    var childContext;
    if (inst.getChildContext) {
       childContext = inst.getChildContext();
    }
    
    if (childContext) {
        return _assign({}, currentContext, childContext);
    }
    return currentContext;
}

function findCurrentUnmaskedContext(fiber) {
 
  var node = fiber;
  while (node.tag !== HostRoot) {
    if (isContextProvider(node)) {
      return node.stateNode.__reactInternalMemoizedMergedChildContext;
    }
    var parent = node["return"];
    node = parent;
  }
  return node.stateNode.context;
}

因?yàn)槲覀兊膒arentComponent一開始不存在,于是返回一個(gè)空對(duì)象。注意,這個(gè)空對(duì)象是重復(fù)使用的,不是每次返回一個(gè)新的空對(duì)象,這是一個(gè)很好的優(yōu)化。

scheduleTopLevelUpdate是將用戶的傳參封裝成一個(gè)update對(duì)象, update對(duì)象有partialState對(duì)象,它就是相當(dāng)于React15中 的setState的第一個(gè)state傳參。但現(xiàn)在partialState中竟然把children放進(jìn)去了。

//by 司徒正美, 加群:370262116 一起研究React與anujs

function scheduleTopLevelUpdate(current, element, callback) {
    // // newRoot.fiber, children, callback

    callback = callback === undefined ? null : callback;
    var expirationTime = void 0;
    // Check if the top-level element is an async wrapper component. If so,
    // treat updates to the root as async. This is a bit weird but lets us
    // avoid a separate `renderAsync` API.
    if (enableAsyncSubtreeAPI && element != null && element.type != null && element.type.prototype != null && element.type.prototype.unstable_isAsyncReactComponent === true) {
      expirationTime = computeAsyncExpiration();
    } else {
      expirationTime = computeExpirationForFiber(current);//計(jì)算過時(shí)時(shí)間
    }

    var update = {
      expirationTime: expirationTime,//過時(shí)時(shí)間
      partialState: { element: element },//!!!!神奇
      callback: callback,
      isReplace: false,
      isForced: false,
      nextCallback: null,
      next: null
    };
    insertUpdateIntoFiber(current, update);//創(chuàng)建一個(gè)列隊(duì)
    scheduleWork(current, expirationTime);//執(zhí)行列隊(duì)
  }

列隊(duì)是一個(gè)鏈表

//by 司徒正美, 加群:370262116 一起研究React與anujs
// https://github.com/RubyLouvre/anu 歡迎加star

function insertUpdateIntoFiber(fiber, update) {
  // We"ll have at least one and at most two distinct update queues.
  var alternateFiber = fiber.alternate;
  var queue1 = fiber.updateQueue;
  if (queue1 === null) {
    // TODO: We don"t know what the base state will be until we begin work.
    // It depends on which fiber is the next current. Initialize with an empty
    // base state, then set to the memoizedState when rendering. Not super
    // happy with this approach.
    queue1 = fiber.updateQueue = createUpdateQueue(null);
  }

  var queue2 = void 0;
  if (alternateFiber !== null) {
    queue2 = alternateFiber.updateQueue;
    if (queue2 === null) {
      queue2 = alternateFiber.updateQueue = createUpdateQueue(null);
    }
  } else {
    queue2 = null;
  }
  queue2 = queue2 !== queue1 ? queue2 : null;

  // If there"s only one queue, add the update to that queue and exit.
  if (queue2 === null) {
    insertUpdateIntoQueue(queue1, update);
    return;
  }

  // If either queue is empty, we need to add to both queues.
  if (queue1.last === null || queue2.last === null) {
    insertUpdateIntoQueue(queue1, update);
    insertUpdateIntoQueue(queue2, update);
    return;
  }

  // If both lists are not empty, the last update is the same for both lists
  // because of structural sharing. So, we should only append to one of
  // the lists.
  insertUpdateIntoQueue(queue1, update);
  // But we still need to update the `last` pointer of queue2.
  queue2.last = update;
}

function insertUpdateIntoQueue(queue, update) {
  // Append the update to the end of the list.
  if (queue.last === null) {
    // Queue is empty
    queue.first = queue.last = update;
  } else {
    queue.last.next = update;
    queue.last = update;
  }
  if (queue.expirationTime === NoWork || queue.expirationTime > update.expirationTime) {
    queue.expirationTime = update.expirationTime;
  }
}

scheduleWork是執(zhí)行虛擬DOM(fiber樹)的更新。 scheduleWork,requestWork, performWork是三部曲。

//by 司徒正美, 加群:370262116 一起研究React與anujs

function scheduleWork(fiber, expirationTime) {
    return scheduleWorkImpl(fiber, expirationTime, false);
  }

  function checkRootNeedsClearing(root, fiber, expirationTime) {
    if (!isWorking && root === nextRoot && expirationTime < nextRenderExpirationTime) {
      // Restart the root from the top.
      if (nextUnitOfWork !== null) {
        // This is an interruption. (Used for performance tracking.)
        interruptedBy = fiber;
      }
      nextRoot = null;
      nextUnitOfWork = null;
      nextRenderExpirationTime = NoWork;
    }
  }

  function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) {
    recordScheduleUpdate();


    var node = fiber;
    while (node !== null) {
      // Walk the parent path to the root and update each node"s
      // expiration time.
      if (node.expirationTime === NoWork || node.expirationTime > expirationTime) {
        node.expirationTime = expirationTime;
      }
      if (node.alternate !== null) {
        if (node.alternate.expirationTime === NoWork || node.alternate.expirationTime > expirationTime) {
          node.alternate.expirationTime = expirationTime;
        }
      }
      if (node["return"] === null) {
        if (node.tag === HostRoot) {
          var root = node.stateNode;

          checkRootNeedsClearing(root, fiber, expirationTime);
          requestWork(root, expirationTime);
          checkRootNeedsClearing(root, fiber, expirationTime);
        } else {

          return;
        }
      }
      node = node["return"];
    }
  }


function requestWork(root, expirationTime) {
    if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
      invariant_1(false, "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.");
    }

    // Add the root to the schedule.
    // Check if this root is already part of the schedule.
    if (root.nextScheduledRoot === null) {
      // This root is not already scheduled. Add it.
      root.remainingExpirationTime = expirationTime;
      if (lastScheduledRoot === null) {
        firstScheduledRoot = lastScheduledRoot = root;
        root.nextScheduledRoot = root;
      } else {
        lastScheduledRoot.nextScheduledRoot = root;
        lastScheduledRoot = root;
        lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
      }
    } else {
      // This root is already scheduled, but its priority may have increased.
      var remainingExpirationTime = root.remainingExpirationTime;
      if (remainingExpirationTime === NoWork || expirationTime < remainingExpirationTime) {
        // Update the priority.
        root.remainingExpirationTime = expirationTime;
      }
    }

    if (isRendering) {
      // Prevent reentrancy. Remaining work will be scheduled at the end of
      // the currently rendering batch.
      return;
    }

    if (isBatchingUpdates) {
      // Flush work at the end of the batch.
      if (isUnbatchingUpdates) {
        // unless we"re inside unbatchedUpdates, in which case we should
        // flush it now.
        nextFlushedRoot = root;
        nextFlushedExpirationTime = Sync;
        performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime);
      }
      return;
    }

    // TODO: Get rid of Sync and use current time?
    if (expirationTime === Sync) {
      performWork(Sync, null);
    } else {
      scheduleCallbackWithExpiration(expirationTime);
    }
  }

 function performWork(minExpirationTime, dl) {
    deadline = dl;

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

    if (enableUserTimingAPI && deadline !== null) {
      var didExpire = nextFlushedExpirationTime < recalculateCurrentTime();
      stopRequestCallbackTimer(didExpire);
    }

    while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || nextFlushedExpirationTime <= minExpirationTime) && !deadlineDidExpire) {
      performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime);
      // Find the next highest priority work.
      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 = -1;
    }
    // If there"s work left over, schedule a new callback.
    if (nextFlushedExpirationTime !== NoWork) {
      scheduleCallbackWithExpiration(nextFlushedExpirationTime);
    }

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

    if (hasUnhandledError) {
      var _error4 = unhandledError;
      unhandledError = null;
      hasUnhandledError = false;
      throw _error4;
    }
  }

function performWorkOnRoot(root, expirationTime) {
    !!isRendering ? invariant_1(false, "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.") : void 0;

    isRendering = true;

    // Check if this is async work or sync/expired work.
    // TODO: Pass current time as argument to renderRoot, commitRoot
    if (expirationTime <= recalculateCurrentTime()) {
      // Flush sync work.
      var finishedWork = root.finishedWork;
      if (finishedWork !== null) {
        // This root is already complete. We can commit it.
        root.finishedWork = null;
        root.remainingExpirationTime = commitRoot(finishedWork);
      } else {
        root.finishedWork = null;
        finishedWork = renderRoot(root, expirationTime);
        if (finishedWork !== null) {
          // We"ve completed the root. Commit it.
          root.remainingExpirationTime = commitRoot(finishedWork);
        }
      }
    } else {
      // Flush async work.
      var _finishedWork = root.finishedWork;
      if (_finishedWork !== null) {
        // This root is already complete. We can commit it.
        root.finishedWork = null;
        root.remainingExpirationTime = commitRoot(_finishedWork);
      } else {
        root.finishedWork = null;
        _finishedWork = renderRoot(root, expirationTime);
        if (_finishedWork !== null) {
          // We"ve completed the root. Check the deadline one more time
          // before committing.
          if (!shouldYield()) {
            // Still time left. Commit the root.
            root.remainingExpirationTime = commitRoot(_finishedWork);
          } else {
            // There"s no time left. Mark this root as complete. We"ll come
            // back and commit it later.
            root.finishedWork = _finishedWork;
          }
        }
      }
    }

   isRendering = false;
}
//用于調(diào)整渲染順序,高優(yōu)先級(jí)的組件先執(zhí)行
function findHighestPriorityRoot() {
    var highestPriorityWork = NoWork;
    var highestPriorityRoot = null;

    if (lastScheduledRoot !== null) {
      var previousScheduledRoot = lastScheduledRoot;
      var root = firstScheduledRoot;
      while (root !== null) {
        var remainingExpirationTime = root.remainingExpirationTime;
        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.
          !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? invariant_1(false, "Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue.") : void 0;
          if (root === root.nextScheduledRoot) {
            // This is the only root in the list.
            root.nextScheduledRoot = null;
            firstScheduledRoot = lastScheduledRoot = null;
            break;
          } else if (root === firstScheduledRoot) {
            // This is the first root in the list.
            var next = root.nextScheduledRoot;
            firstScheduledRoot = next;
            lastScheduledRoot.nextScheduledRoot = next;
            root.nextScheduledRoot = null;
          } else if (root === lastScheduledRoot) {
            // This is the last root in the list.
            lastScheduledRoot = previousScheduledRoot;
            lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
            root.nextScheduledRoot = null;
            break;
          } else {
            previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot;
            root.nextScheduledRoot = null;
          }
          root = previousScheduledRoot.nextScheduledRoot;
        } else {
          if (highestPriorityWork === NoWork || remainingExpirationTime < highestPriorityWork) {
            // Update the priority, if it"s higher
            highestPriorityWork = remainingExpirationTime;
            highestPriorityRoot = root;
          }
          if (root === lastScheduledRoot) {
            break;
          }
          previousScheduledRoot = root;
          root = root.nextScheduledRoot;
        }
      }
    }

    // If the next root is the same as the previous root, this is a nested
    // update. To prevent an infinite loop, increment the nested update count.
    var previousFlushedRoot = nextFlushedRoot;
    if (previousFlushedRoot !== null && previousFlushedRoot === highestPriorityRoot) {
      nestedUpdateCount++;
    } else {
      // Reset whenever we switch roots.
      nestedUpdateCount = 0;
    }
    nextFlushedRoot = highestPriorityRoot;
    nextFlushedExpirationTime = highestPriorityWork;
  }

這只是一部分更新邏輯, 簡(jiǎn)直沒完沒了,下次繼續(xù),添上流程圖,回憶一下本文學(xué)到的東西

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/107189.html

相關(guān)文章

  • React16.2fiber架構(gòu)(2)

    摘要:為了幫助理解,我們繼續(xù)加日志司徒正美,加群一起研究與只要收到更新對(duì)象,就會(huì)被調(diào)度程序調(diào)用。渲染器在將來(lái)的某個(gè)時(shí)刻調(diào)用。導(dǎo)步肯定為歡迎加繼續(xù)略也是怒長(zhǎng),代碼的特點(diǎn)是許多巨型類,巨型方法,有之遺風(fēng)。 insertUpdateIntoFiber 會(huì)根據(jù)fiber的狀態(tài)創(chuàng)建一個(gè)或兩個(gè)列隊(duì)對(duì)象,對(duì)象是長(zhǎng)成這樣的 //by 司徒正美, 加群:370262116 一起研究React與anujs //...

    Caicloud 評(píng)論0 收藏0
  • 精讀《React16 新特性》

    摘要:引言于發(fā)布版本,時(shí)至今日已更新到,且引入了大量的令人振奮的新特性,本文章將帶領(lǐng)大家根據(jù)更新的時(shí)間脈絡(luò)了解的新特性。其作用是根據(jù)傳遞的來(lái)更新。新增等指針事件。 1 引言 于 2017.09.26 Facebook 發(fā)布 React v16.0 版本,時(shí)至今日已更新到 React v16.6,且引入了大量的令人振奮的新特性,本文章將帶領(lǐng)大家根據(jù) React 更新的時(shí)間脈絡(luò)了解 React1...

    Nosee 評(píng)論0 收藏0
  • 淺談React Fiber

    摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來(lái)很順暢。通過進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...

    izhuhaodev 評(píng)論0 收藏0
  • React系列——React Fiber 架構(gòu)介紹資料匯總(翻譯+中文資料)

    摘要:它的主體特征是增量渲染能夠?qū)秩竟ぷ鞣指畛蓧K,并將其分散到多個(gè)幀中。實(shí)際上,這樣做可能會(huì)造成浪費(fèi),導(dǎo)致幀丟失并降低用戶體驗(yàn)。當(dāng)一個(gè)函數(shù)被執(zhí)行時(shí),一個(gè)新的堆棧框架被添加到堆棧中。該堆??虮硎居稍摵瘮?shù)執(zhí)行的工作。 原文 react-fiber-architecture 介紹 React Fibre是React核心算法正在進(jìn)行的重新實(shí)現(xiàn)。它是React團(tuán)隊(duì)兩年多的研究成果。 React ...

    taohonghui 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

lansheng228

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<