React16.2的fiber架构详解

本文主要和大家分享react16.2的fiber架构详解,希望能帮助到大家。insertupdateintofiber 会根据fiber的状态创建一个或两个列队对象,对象是长成这样的对象是长成这样的

//by 司徒正美, 加群:370262116 一起研究React与anujs// https://github.com/RubyLouvre/anu 欢迎加starfunction createUpdateQueue(baseState) {//我们现在是丢了一个null做传参  var queue = {    baseState: baseState,    expirationTime: NoWork,//NoWork会被立即执行    first: null,    last: null,    callbackList: null,    hasForceUpdate: false,    isInitialized: false  };  return queue;}

登录后复制

scheduleWork是一个奇怪的方法,只是添加一下参数

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

登录后复制

scheduleWorkImpl的最开头有一个recordScheduleUpdate方法,用来记录调度器的执行状态,如注释所示,它现在相当于什么都没有做

function recordScheduleUpdate() {  if (enableUserTimingAPI) {//全局变量,默认为true    if (isCommitting) {//全局变量,默认为false, 没有进入分支      hasScheduledUpdateInCurrentCommit = true;    }    //全局变量,默认为null,没有没有进入分支    if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') {      hasScheduledUpdateInCurrentPhase = true;    }  }}

登录后复制

scheduleWorkImpl的一些分支非常复杂,我们打一些断点

function computeExpirationForFiber(fiber) {    var expirationTime = void 0;    if (expirationContext !== NoWork) {      // An explicit expiration context was set;      expirationTime = expirationContext;    } else if (isWorking) {      if (isCommitting) {        // Updates that occur during the commit phase should have sync priority        // by default.        expirationTime = Sync;      } else {        // Updates during the render phase should expire at the same time as        // the work that is being rendered.        expirationTime = nextRenderExpirationTime;      }    } else {      // No explicit expiration context was set, and we're not currently      // performing work. Calculate a new expiration time.      if (useSyncScheduling && !(fiber.internalContextTag & AsyncUpdates)) {        // This is a sync update        console.log("expirationTime", Sync)        expirationTime = Sync;//命中这里      } else {        // This is an async update        expirationTime = computeAsyncExpiration();      }    }    return expirationTime;  }    function checkRootNeedsClearing(root, fiber, expirationTime) {    if (!isWorking && root === nextRoot && expirationTime  expirationTime) {        node.expirationTime = expirationTime;//由于默认就是NoWork,因此会被重写 Sync      }      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);          console.log("requestWork",root, expirationTime)          requestWork(root, expirationTime);          checkRootNeedsClearing(root, fiber, expirationTime);        } else {          return;        }      }      node = node['return'];    }  }

登录后复制

输出如下

React16.2的fiber架构详解

requestWork也很难理解,里面太多全局变量,觉得不是前端的人搞的。为了帮助理解,我们继续加日志

//by 司徒正美, 加群:370262116 一起研究React与anujs // requestWork is called by the scheduler whenever a root receives an update.  // It's up to the renderer to call renderRoot at some point in the future.  /*只要root收到更新(update对象),requestWork就会被调度程序调用。渲染器在将来的某个时刻调用renderRoot。  */  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.      console.log("设置remainingExpirationTime",expirationTime)      root.remainingExpirationTime = expirationTime;      if (lastScheduledRoot === null) {        console.log("设置firstScheduledRoot, lastScheduledRoot")        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;        console.log("performWorkOnRoot")        performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime);      }      return;    }    // TODO: Get rid of Sync and use current time?    if (expirationTime === Sync) {      console.log("进入performWork")      performWork(Sync, null);    } else {      scheduleCallbackWithExpiration(expirationTime);    }  }

登录后复制

从日志输出来看,requestWork只是修改了两个全局变量,然后进入performWork。这三个内部方法起名很有意思。scheduleWork意为打算工作,requestWork意为申请工作,performWork意为努力工作(正式上班)

function performWork(minExpirationTime, dl) {    deadline = dl;    // Keep working on roots until there's no more work, or until the we reach    // the deadline.    //这里会将root设置为highestPriorityRoot    findHighestPriorityRoot();    if (enableUserTimingAPI && deadline !== null) {      var didExpire = nextFlushedExpirationTime < recalculateCurrentTime();      console.log(didExpire)      stopRequestCallbackTimer(didExpire);    }    while (nextFlushedRoot !== null       && nextFlushedExpirationTime !== NoWork       && (minExpirationTime === NoWork || nextFlushedExpirationTime <= minExpirationTime)       && !deadlineDidExpire) {      console.log("performWorkOnRoot")      performWorkOnRoot(highestPriorityRoot, 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) {      console.log("scheduleCallbackWithExpiration")      scheduleCallbackWithExpiration(nextFlushedExpirationTime);    }    // Clean-up.    deadline = null;    deadlineDidExpire = false;    nestedUpdateCount = 0;    if (hasUnhandledError) { //如果有没处理的错误则throw      var _error4 = unhandledError;      unhandledError = null;      hasUnhandledError = false;      throw _error4;    }  }

登录后复制

React16.2的fiber架构详解

我们终于进入performWorkOnRoot,performWorkOnRoot的作用是区分同步渲染还是异步渲染,expirationTime等于1,因此进入同步。导步肯定为false

// https://github.com/RubyLouvre/anu 欢迎加starfunction performWorkOnRoot(root, expirationTime) {    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;      console.log("Flush sync work.", finishedWork)      if (finishedWork !== null) {        // This root is already complete. We can commit it.        root.finishedWork = null;        console.log("commitRoot")        root.remainingExpirationTime = commitRoot(finishedWork);      } else {        root.finishedWork = null;        console.log("renderRoot")        finishedWork = renderRoot(root, expirationTime);        if (finishedWork !== null) {          console.log("继续commitRoot")          // We've completed the root. Commit it.          root.remainingExpirationTime = commitRoot(finishedWork);        }      }    } else {      console.log("Flush async work.")      // Flush async work.      // ...略    }    isRendering = false;  }

登录后复制

React16.2的fiber架构详解

renderRoot也是怒长,React16代码的特点是许多巨型类,巨型方法,有JAVA之遗风。renderRoot只有前面几行是可能处理虚拟DOM(或叫fiber),后面都是错误边界的

function renderRoot(root, expirationTime) {       isWorking = true;    // We're about to mutate the work-in-progress tree. If the root was pending    // commit, it no longer is: we'll need to complete it again.    root.isReadyForCommit = false;    // Check if we're starting from a fresh stack, or if we're resuming from    // previously yielded work.    if (root !== nextRoot || expirationTime !== nextRenderExpirationTime || nextUnitOfWork === null) {      // Reset the stack and start working from the root.      resetContextStack();      nextRoot = root;      nextRenderExpirationTime = expirationTime;      //可能是用来工作的代码       console.log("createWorkInProgress")      nextUnitOfWork = createWorkInProgress(nextRoot.current, null, expirationTime);    }    //可能是用来工作的代码     console.log("startWorkLoopTimer")    startWorkLoopTimer(nextUnitOfWork);   // 处理错误边界    var didError = false;    var error = null;    invokeGuardedCallback$1(null, workLoop, null, expirationTime);    // An error was thrown during the render phase.    while (didError) {       console.log("componentDidCatch的相关实现")      if (didFatal) {        // This was a fatal error. Don't attempt to recover from it.        firstUncaughtError = error;        break;      }      var failedWork = nextUnitOfWork;      if (failedWork === null) {        // An error was thrown but there's no current unit of work. This can        // happen during the commit phase if there's a bug in the renderer.        didFatal = true;        continue;      }      // 处理错误边界      var boundary = captureError(failedWork, error);      !(boundary !== null) ? invariant_1(false, 'Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue.') : void 0;      if (didFatal) {        // The error we just captured was a fatal error. This happens        // when the error propagates to the root more than once.        continue;      }       // 处理错误边界      didError = false;      error = null;      // We're finished working. Exit the error loop.      break;    }   // 处理错误边界    var uncaughtError = firstUncaughtError;    // We're done performing work. Time to clean up.    stopWorkLoopTimer(interruptedBy);    interruptedBy = null;    isWorking = false;    didFatal = false;    firstUncaughtError = null;     // 处理错误边界    if (uncaughtError !== null) {      onUncaughtError(uncaughtError);    }    return root.isReadyForCommit ? root.current.alternate : null;  }  function resetContextStack() {    // Reset the stack    reset$1();    // Reset the cursors    resetContext();    resetHostContainer();  }function reset$1() {  console.log("reset",index)  while (index > -1) {    valueStack[index] = null;    {      fiberStack[index] = null;    }    index--;  }}function resetContext() {  consoel.log("resetContext")  previousContext = emptyObject_1;  contextStackCursor.current = emptyObject_1;  didPerformWorkStackCursor.current = false;}  function resetHostContainer() {    console.log("resetHostContainer",contextStackCursor, rootInstanceStackCursor, NO_CONTEXT )    contextStackCursor.current = NO_CONTEXT;    rootInstanceStackCursor.current = NO_CONTEXT;  }

登录后复制

React16.2的fiber架构详解

createWorkInProgress就是将根组件的fiber对象再复制一份,变成其alternate属性。因此 将虚拟DOM转换为真实DOM的重任就交给invokeGuardedCallback

var invokeGuardedCallback = function (name, func, context, a, b, c, d, e, f) {  ReactErrorUtils._hasCaughtError = false;  ReactErrorUtils._caughtError = null;  var funcArgs = Array.prototype.slice.call(arguments, 3);  try {    func.apply(context, funcArgs);  } catch (error) {    ReactErrorUtils._caughtError = error;    ReactErrorUtils._hasCaughtError = true;  }//这下面还有怒长(100-150L )的关于错误边界的处理,略过};

登录后复制

func为workLoop

//by 司徒正美, 加群:370262116 一起研究React与anujs function workLoop(expirationTime) {    if (capturedErrors !== null) {      // If there are unhandled errors, switch to the slow work loop.      // TODO: How to avoid this check in the fast path? Maybe the renderer      // could keep track of which roots have unhandled errors and call a      // forked version of renderRoot.      slowWorkLoopThatChecksForFailedWork(expirationTime);      return;    }    if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) {      return;    }    if (nextRenderExpirationTime <= mostRecentCurrentTime) {      // Flush all expired work.      while (nextUnitOfWork !== null) {        console.log("performUnitOfWork",nextUnitOfWork)        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);      }    } else {      // Flush asynchronous work until the deadline runs out of time.      while (nextUnitOfWork !== null && !shouldYield()) {        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);      }    }  }

登录后复制

React16.2的fiber架构详解
我们终于看到工作的代码了。 这个nextUnitOfWork 是renderRoot生成的
performUnitOfWork与beginWork的代码,里面会根据fiber的tag进入各种操作

//by 司徒正美, 加群:370262116 一起研究React与anujs// https://github.com/RubyLouvre/anu 欢迎加starfunction performUnitOfWork(workInProgress) {    // The current, flushed, state of this fiber is the alternate.    // Ideally nothing should rely on this, but relying on it here    // means that we don't need an additional field on the work in    // progress.    var current = workInProgress.alternate;    // See if beginning this work spawns more work.    startWorkTimer(workInProgress);    {      ReactDebugCurrentFiber.setCurrentFiber(workInProgress);    }    console.log("beginWork")    var next = beginWork(current, workInProgress, nextRenderExpirationTime);    {      ReactDebugCurrentFiber.resetCurrentFiber();    }    if (true && ReactFiberInstrumentation_1.debugTool) {      ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress);    }    if (next === null) {      console.log("next")      // If this doesn't spawn new work, complete the current work.      next = completeUnitOfWork(workInProgress);    }    ReactCurrentOwner.current = null;    return next;  }function beginWork(current, workInProgress, renderExpirationTime) {    if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) {      return bailoutOnLowPriority(current, workInProgress);    }    switch (workInProgress.tag) {      case IndeterminateComponent:        return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);      case FunctionalComponent:        return updateFunctionalComponent(current, workInProgress);      case ClassComponent:        return updateClassComponent(current, workInProgress, renderExpirationTime);      case HostRoot:        return updateHostRoot(current, workInProgress, renderExpirationTime);      case HostComponent:        return updateHostComponent(current, workInProgress, renderExpirationTime);      case HostText:        return updateHostText(current, workInProgress);      case CallHandlerPhase:        // This is a restart. Reset the tag to the initial phase.        workInProgress.tag = CallComponent;      // Intentionally fall through since this is now the same.      case CallComponent:        return updateCallComponent(current, workInProgress, renderExpirationTime);      case ReturnComponent:        // A return component is just a placeholder, we can just run through the        // next one immediately.        return null;      case HostPortal:        return updatePortalComponent(current, workInProgress, renderExpirationTime);      case Fragment:        return updateFragment(current, workInProgress);      default:        invariant_1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');    }  }

登录后复制

我们再调查一下workInProgress.tag是什么

https://github.com/facebook/r…

这里有全部fiber节点的类型描述,我们创建一个对象

// https://github.com/RubyLouvre/anu 欢迎加starvar mapBeginWork = {    3: "HostRoot 根组件",    0: "IndeterminateComponent 只知道type为函数",    2: "ClassComponent 普通类组件" ,    5: "HostComponent 元素节点",    6: "HostText 文本节点"  }  function beginWork(current, workInProgress, renderExpirationTime) {    if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) {      return bailoutOnLowPriority(current, workInProgress);    }    console.log(workInProgress.tag, mapBeginWork[workInProgress.tag])     switch (workInProgress.tag) {     //略     }}

登录后复制

React16.2的fiber架构详解

相关推荐:

nodejs中的fiber(纤程)库详解_node.js

以上就是React16.2的fiber架构详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2787589.html

(0)
上一篇 2025年3月8日 18:11:08
下一篇 2025年3月8日 18:11:18

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • js面向对象之继承知识详解

    说到这个继承,了解object-oriented的朋友都知道,大多oo语言都有两种,一种是接口继承(只继承方法签名);一种是实现继承(继承实际的方法)本文主要和大家介绍js面向对象之继承的相关知识,以及分享了读者弄明白这个知识点的学习心得,…

    2025年3月8日
    200
  • vue之v-if和v-show的区别详解

    本文主要和大家介绍vue学习笔记之v-if和v-show的区别,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。 v-if vs v-show v-if 是“真正的”条件渲染,因为它会确保在切换…

    2025年3月8日
    200
  • jQuery UI日期选择器实例详解

    默认功能 日期选择器(Datepicker)绑定到一个标准的表单 input 字段上。把焦点移到 input 上(点击或者使用 tab 键),在一个小的覆盖层上打开一个交互日历。选择一个日期,点击页面上的任意地方(输入框即失去焦点),或者点…

    编程技术 2025年3月8日
    200
  • js的变量提升和函数提升详解

    本文为大家带来一篇基于js的变量提升和函数提升(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。 一、变量提升 在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个…

    编程技术 2025年3月8日
    200
  • Docker的Mysql主从复制详解

    本文主要和大家分享基于Docker的Mysql主从复制,希望能帮助到大家。 环境简介 主服务器:jd云 centos 从服务器:Vultr云 CentOS 为了方便测试,都使用Docker运行Mysql,Docker启动命令如下:     …

    编程技术 2025年3月8日
    200
  • vue-router源码实例详解

    本文主要和大家分享vue-router源码阅读学习,如同分析vuex源码我们首先通过一个简单例子进行了解vue-router是如何使用的,然后在分析在源码中是如何实现的,希望能帮助到大家。 示例 下面示例来自于example/basica/…

    编程技术 2025年3月8日
    200
  • 实例详解js中ajax访问

    本文主要和大家介绍原生js中ajax访问的实例详解的相关资料,希望通过本文大家能够掌握理解这部分内容,需要的朋友可以参考下,希望能帮助到大家。 原生js中ajax访问的实例详解 form表单中 登录名: 失去光标即触发事件 function…

    编程技术 2025年3月8日
    200
  • JavaScript事件处理程序详解

    本文主要和大家详细介绍javascript事件处理程序的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮助到大家。 nbsp;html>    DOM0级DOM2级 function show() { alert(…

    编程技术 2025年3月8日
    200
  • Nuxt.js Vue服务端渲染详解

    nuxt.js 十分简单易用。一个简单的项目只需将 nuxt 添加为依赖组件即可。本文主要和大家介绍了nuxt.js vue服务端渲染摸索,给大家做个参考,希望能帮助到大家。 Vue因其简单易懂的API、高效的数据绑定和灵活的组件系统,受到…

    编程技术 2025年3月8日
    200
  • Redux和Mobx的选择实例详解

    redux 和 mobx 都是当下比较火热的数据流模型,似乎现在社区里关于该选什么来替代 redux 很自然地成为了一件困惑的事。开发者不确定该选择哪种解决方案。这个问题并不只是出现在 redux 与 mobx 上。无论何时,只要存在选择,…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论