React16源码: React中的performWork的源码实现

ReactFiber在并发模式下的运行机制 ReactFiber在并发模式下的运行机制 新一年又开始了,React过去一年悄悄实现了Suspense,带来了React Hooks ,源码也大变换了。因此好有必须重新阅读一下,看它是如何实现这些功能,及未来准备开放的并发渲染功能。 React16早期将原来的diff过程拆分成两个阶段,第一个阶段叫reconcile, 也就是原来diff虚拟DOM的过程。这阶段有大量叫reconcile... 阅读详情

performWork


1 )概述

  • performWork 涉及到在调度完成,或者同步任务进来之后整个 root 节点链条如何更新
  • 怎么更新一棵 Fiber 树,它的每一个节点是如何被遍历到,以及如何进行更新操作
  • A. 在执行 performWork 时候,是否有 deadline 的区分
    • deadline 是通过 reactschedule 它的一个时间片,更新的过程当中
    • 产生的一个叫做 deadlineobject 的对象
    • 它可以用来判断我们在一帧的渲染时间内留给react进行fiber树渲染的时间还有没有
  • B.循环渲染root的条件
    • 一个应用当中可能会有多个root节点
    • 同时每一个root节点上面呢又会有不同优先级的任务产生
    • 要循环去遍历各个不同的root节点
    • 以及他们的不同的优先级的任务,然后按照优先级去一个个去更新
    • 这个循环它如何建立,如何判断这个循环是否成立的条件
  • C.超过时间片之后的一个处理
    • 在deadline到了之后,就是我们这一帧的渲染时间已经到了
    • 我们需要把js的执行权又交回给浏览器,这个时候又该怎么做

2 )源码

定位到 packages/react-reconciler/src/ReactFiberScheduler.js

function performAsyncWork() {
  try {
    if (!shouldYieldToRenderer()) {
      // The callback timed out. That means at least one update has expired.
      // Iterate through the root schedule. If they contain expired work, set
      // the next render expiration time to the current time. This has the effect
      // of flushing all expired work in a single batch, instead of flushing each
      // level one at a time.
      if (firstScheduledRoot !== null) {
        recomputeCurrentRendererTime();
        let root: FiberRoot = firstScheduledRoot;
        do {
          didExpireAtExpirationTime(root, currentRendererTime);
          // The root schedule is circular, so this is never null.
          root = (root.nextScheduledRoot: any);
        } while (root !== firstScheduledRoot);
      }
    }
    performWork(NoWork, true);
  } finally {
    didYield = false;
  }
}


function performSyncWork() {
  performWork(Sync, null);
}

function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {
  deadline = dl;

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

  if (deadline !== null) {
    recomputeCurrentRendererTime();
    currentSchedulerTime = currentRendererTime;

    if (enableUserTimingAPI) {
      const didExpire = nextFlushedExpirationTime < currentRendererTime;
      const timeout = expirationTimeToMs(nextFlushedExpirationTime);
      stopRequestCallbackTimer(didExpire, timeout);
    }

    while (
      nextFlushedRoot !== null &&
      nextFlushedExpirationTime !== NoWork &&
      (minExpirationTime === NoWork ||
        minExpirationTime >= nextFlushedExpirationTime) &&
      (!deadlineDidExpire || currentRendererTime >= nextFlushedExpirationTime)
    ) {
      performWorkOnRoot(
        nextFlushedRoot,
        nextFlushedExpirationTime,
        currentRendererTime >= nextFlushedExpirationTime,
      );
      findHighestPriorityRoot();
      recomputeCurrentRendererTime();
      currentSchedulerTime = currentRendererTime;
    }
  } else {
    while (
      nextFlushedRoot !== null &&
      nextFlushedExpirationTime !== NoWork &&
      (minExpirationTime === NoWork ||
        minExpirationTime >= nextFlushedExpirationTime)
    ) {
      performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, true);
      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 = null;
  }
  // If there's work left over, schedule a new callback.
  if (nextFlushedExpirationTime !== NoWork) {
    scheduleCallbackWithExpirationTime(
      ((nextFlushedRoot: any): FiberRoot),
      nextFlushedExpirationTime,
    );
  }

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

  finishRendering();
}
  • performAsyncWork, performSyncWork, performWork 三个方法连在一起
  • 对于 performSyncWork 直接 调用 performWork(Sync, null); 就一行代码
  • performAsyncWork 就相对复杂,是通过 react scheduler 调度回来的
    • 参数是 deadline 对象 dl
    • 本质上只有一个 if判断 和 执行 performWork 方法
    • 在if判断中, recomputeCurrentRendererTime 这个方法不涉及主要流程,跳过
      • 在找到 root 之后,执行 didExpireaTexpirationTime 标记在root节点上的一些变量
        // packages/react-reconciler/src/ReactFiberPendingPriority.js
        export function didExpireAtExpirationTime(
          root: FiberRoot,
          currentTime: ExpirationTime,
        ): void {
          const expirationTime = root.expirationTime;
          // 有任务,但任务过期
          if (expirationTime !== NoWork && currentTime >= expirationTime) {
            // The root has expired. Flush all work up to the current time.
            root.nextExpirationTimeToWorkOn = currentTime; // 挂载 当前时间 作为 nextExpirationTimeToWorkOn 属性
          }
        }
        
      • 之后,一个do while 找最终的 root
    • 之后,执行 performWork(NoWork, dl)
      • NoWork 是 0
      • export const NoWork = 0
  • 在 performWork 中
    • 有两个参数,minExpirationTime: ExpirationTime, dl: Deadline | null
    • findHighestPriorityRoot 这个方法
      function findHighestPriorityRoot() {
        let highestPriorityWork = NoWork;
        let highestPriorityRoot = null;
        // 这个if表示仍存在节点更新情况
        if (lastScheduledRoot !== null) {
          let previousScheduledRoot = lastScheduledRoot;
          let root = firstScheduledRoot;
          // 存在 root 就进行循环
          while (root !== null) {
            const remainingExpirationTime = root.expirationTime;
            // 这个if判断表示,是没有任何更新的
            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.
              invariant(
                previousScheduledRoot !== null && lastScheduledRoot !== null,
                'Should have a previous and last root. This error is likely ' +
                  'caused by a bug in React. Please file an issue.',
              );
              // 这种情况,只有一个 root 节点
              if (root === root.nextScheduledRoot) {
                // This is the only root in the list.
                root.nextScheduledRoot = null;
                firstScheduledRoot = lastScheduledRoot = null;
                break;
              } else if (root === firstScheduledRoot) {
                // 这时候 root 就没用了,可以删除了,获取 next
                // This is the first root in the list.
                const next = root.nextScheduledRoot;
                firstScheduledRoot = next;
                lastScheduledRoot.nextScheduledRoot = next;
                root.nextScheduledRoot = null;
              } else if (root === lastScheduledRoot) {
                // 这个时候,root是最后一个
                // This is the last root in the list.
                lastScheduledRoot = previousScheduledRoot;
                lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
                root.nextScheduledRoot = null;
                break;
              } else {
                // 移除 中间的 root.nextScheduledRoot 节点
                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;
              }
              if (highestPriorityWork === Sync) {
                // Sync is highest priority by definition so
                // we can stop searching.
                break;
              }
              previousScheduledRoot = root;
              root = root.nextScheduledRoot;
            }
          }
        }
        // 处理更新后的 highestPriorityRoot 和 highestPriorityWork
        nextFlushedRoot = highestPriorityRoot;
        nextFlushedExpirationTime = highestPriorityWork;
      }
      
    • 看下 deadine 不为 null 时的情况
      • 这是异步的情况
      • 主要看 while 里的 (!deadlineDidExpire || currentRendererTime >= nextFlushedExpirationTime)
        • !deadlineDidExpire 表示时间片还有剩余时间
        • nextFlushedExpirationTime 是现在要输出任务的过期时间
          • currentRendererTime >= nextFlushedExpirationTime
          • 说明 当前 render 时间 比 过期时间大,已经超时了,需要强制输出
        • 之后执行 performWorkOnRoot
          • 关于这个函数,主要关注第三个参数
          • 默认是 true
          • 对于异步情况,值为: currentRendererTime >= nextFlushedExpirationTime
            • 任务过期,则为 true, 否则为 false
        • 进入 这个函数
          function performWorkOnRoot(
            root: FiberRoot,
            expirationTime: ExpirationTime,
            isExpired: boolean, // 是否过期,这个方法里一定有针对过期任务的强制更新
          ) {
            invariant(
              !isRendering,
              'performWorkOnRoot was called recursively. This error is likely caused ' +
                'by a bug in React. Please file an issue.',
            );
          
            isRendering = true; // 注意这里和函数结束
          
            // Check if this is async work or sync/expired work.
            // deadline === null  是 Sync的情况,isExpired 是过期的情况
            if (deadline === null || isExpired) {
              // Flush work without yielding.
              // TODO: Non-yieldy work does not necessarily imply expired work. A renderer
              // may want to perform some work without yielding, but also without
              // requiring the root to complete (by triggering placeholders).
          
              let finishedWork = root.finishedWork;
              if (finishedWork !== null) {
                // This root is already complete. We can commit it.
                completeRoot(root, finishedWork, expirationTime); // 有 finishedWork 直接 completeRoot
              } else {
                root.finishedWork = null;
                // If this root previously suspended, clear its existing timeout, since
                // we're about to try rendering again.
                const timeoutHandle = root.timeoutHandle;
                // 处理 timeoutHandle 的情况,跳过
                if (timeoutHandle !== noTimeout) {
                  root.timeoutHandle = noTimeout;
                  // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
                  cancelTimeout(timeoutHandle);
                }
                // 在这个条件下,不可中断 因为在上层if框架下,要么是 Sync的任务,要么是 过期的任务需要立即执行
                const isYieldy = false;
                renderRoot(root, isYieldy, isExpired);
                finishedWork = root.finishedWork;
                if (finishedWork !== null) {
                  // We've completed the root. Commit it.
                  completeRoot(root, finishedWork, expirationTime);
                }
              }
            } else {
              // 这里匹配 Async 异步任务,和上面Sync的任务流程基本差不多
              // Flush async work.
              let finishedWork = root.finishedWork;
              // 一开始进来判断这个 finishedWork,有可能在上一个时间片中,renderRoot执行完了,但是,没有时间去执行 completeRoot 了
              // 需要再下次异步调度的时候进来,如果有 finishedWork 则先 completeRoot
              if (finishedWork !== null) {
                // This root is already complete. We can commit it.
                completeRoot(root, finishedWork, expirationTime);
              } else {
                root.finishedWork = null;
                // If this root previously suspended, clear its existing timeout, since
                // we're about to try rendering again.
                const timeoutHandle = root.timeoutHandle;
                if (timeoutHandle !== noTimeout) {
                  root.timeoutHandle = noTimeout;
                  // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
                  cancelTimeout(timeoutHandle);
                }
                // 这个任务是可以中断的
                const isYieldy = true;
                renderRoot(root, isYieldy, isExpired);
                finishedWork = root.finishedWork;
                // finishedWork 有可能为 null, 中断了就没有完成任务
                if (finishedWork !== null) {
                  // We've completed the root. Check the deadline one more time
                  // before committing.
                  // 先判断是否需要跳出,这时候时间片可能已经用完,如果没有用完,执行 completeRoot
                  if (!shouldYield()) {
                    // Still time left. Commit the root.
                    completeRoot(root, finishedWork, expirationTime);
                  } else {
                    // There's no time left. Mark this root as complete. We'll come
                    // back and commit it later.
                    // 需要跳出,则赋值 finishedWork,注意这里不执行 completeRoot,因为没有时间了,需要等待下个时间片进来才能执行
                    root.finishedWork = finishedWork;
                  }
                }
              }
            }
          
            isRendering = false;
          }
          
        • 执行 findHighestPriorityRoot
        • currentSchedulerTime = currentRendererTime
    • 看下 deadine 为 null 时的情况
      • 这是同步的情况
      • while(nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || minExpirationTime >= nextFlushedExpirationTime))
        • 对于 perfromSyncWork 来说,minExpirationTime 是 1,1 >= nextFlushedExpirationTime 说明 只有 Sync(1)的情况,或者 NoWork,所以 nextFlushedExpirationTime 只有是1的情况
        • 相当于在 perfromSyncWork 的时候,只会执行 root.expirationTime 是 Sync 的任务,也就是说是同步更新的更新,才会在这里继续执行,这样和 SyncWork 这函数名匹配
        • 在这种情况下,调用 performWorkOnRoot 和 findHighestPriorityRoot 执行掉 Sync的任务
  • 注意,在 performWork 上两个循环的判断条件
  • 以及传入 performWorkOnRoot的第三个参数的意义
React render阶段解析三-completeWork流程 这次是接着上一期render阶段的文章,解析挂载时render阶段的"归"阶段----completeWork函数 completeWork开始阶段 在performUnitOfWork中执行完beginWork,就会进入下面判断 if (next === null) { // workInProgress已经不存在子树,就开始进行"归"阶段 completeUnitOfWork(unitOfWork); } else { // next是beginWork调用后的返回值w 阅读详情

相关推荐

从零开始 使用OMNET++结合VEINS,INET和SUMO的联合仿真

搭建仿真的环境,导入VEINS和INET开源库,使用INET库中提供的网络协议和功能模型来模拟通信协议和网络功能,使用SUMO创建道路网络和车辆轨迹,并导出到OMNeT++中 在OMNeT++中使用VEINS通过socket和SUMO连接,借助VEINS实现的TRACI接口来设置车辆相关的行为和场景,最后在OMNET++中结合VEINS,SUMO和INET运行联合仿真实验,并分析车辆在遇到紧急情况下的通信状况和具体行为

mjmmm的博客 1万+

React源码阅读之:复合类型方案设计

关于React中一些代码设计 最近在看React的源码,注意到了一些有意思的细节,比如经常会出现的一下比较和赋值代码 workInProgress.effectTag |= Ref (workInProgress.effectTag & DidCapture) !== NoEffect 对于平时基本上没怎么用到过移位运算的我一开始...

weixin_34352005的博客 157

UA MATH567 高维统计I 概率不等式1 Hoeffding不等式与Chernoff不等式

UA MATH567 高维统计I 概率不等式1 Hoeffding不等式与Chernoff不等式 这个系列介绍高维统计,一些需要知道的结论可以参考UA MATH 564与566两个系列,分为两大部分,高维的概率论相关结果、高维的统计模型。概率论相关结论分六个部分介绍:概率不等式、高维随机向量、随机矩阵、Concentration without Independence、二次型、随机过程。 ...

一个不愿透露姓名的博客 2734

React Work Loop 原理

背景 - 前端体验优化 为了让 React 在检测到数据变化需要重新渲染界面的时候不会阻塞浏览器主线程,从而让用户交互体验更流畅,React 团队提出了 Work Loop 的概念,将任务拆分成小的模块,在每一个任务完成后都检测是否当前有优先级更高的任务(例如:用户与浏览器的交互),有则优先执行优先级更高的任务,没有则继续执行下一个任务。 (声明:本文所解析的所有逻辑都是为了大家能更好的通...

GuoZebin的博客 997

从立创商城到Cadence:手把手教你实现封装格式的精准迁移

本文详细介绍了如何从立创商城获取元器件封装并精准迁移至Cadence Allegro的全流程。通过实战案例MAX31865ATP+T芯片,逐步解析Altium Designer格式转换、Cadence环境配置、封装导入验证等关键步骤,提供常见问题解决方案和效率提升技巧,帮助硬件工程师实现封装格式的高效迁移。

weixin_42519985的博客 217

基于mediapipe的动作捕捉和人物模型的驱动

我实习做这个的时候,当时也找了很多资料,但很多资料都没有讲透,下面我就总结一下自己结合看代码后的感悟,还有一些我认为很重要的点。

qq_58484580的博客 7712

React16源码: React中ReactFiberScheduler的expirationTime及nextExpirationTimeToWorkOn的源码实现

expirationTime 作用在渲染之前的,而 nextExpirationTimeToWorkOn 则是作用在渲染时的。让它在下一次执行更新之前来使用 performSyncWork 这种方式来通过同步的方式去渲染任务。这两个值在整个 render 以及 commit 的过程当中,都起着非常重要的一个作用。所以这就是这两个值它的作用, 通过指定它们来指定更新模式以及更新任务的优先级。为什么说 expirationTime 是作用在渲染前的呢?比如说, 在 renderRoot 中。

Wang的专栏 1274

halcon 检测直线

图中后三个对象既是检测出的图像;

qq_59062726的博客 666

React Fiber源码分析 第二篇(同步模式)

系列文章 React Fiber源码分析 第一篇 React Fiber源码分析 第二篇(同步模式) React Fiber源码分析 第三篇(异步状态) React Fiber源码分析 第四篇(归纳总结) 前言 React Fiber是React在V16版本中的大更新,利用了闲余时间看了一些源码,做个小记录~如果有错误,请轻喷 流程...

weixin_33896726的博客 128

Vue3多级路由缓存失效的深度解析与实战解决方案

本文深度解析了Vue3项目中多级路由嵌套下keep-alive缓存失效的根本原因,并提供了三种实战解决方案。通过剖析组件树、router-view与keep-alive的协作机制,揭示了缓存无法穿透多层router-view的技术本质。文章对比了路由扁平化重构、状态管理配合路由守卫以及使用社区插件等方案的优缺点与适用场景,为开发者解决这一常见难题提供了清晰的选型指导。

weixin_29001423的博客 273

ABAP CDS Time Functions 全面解析:用 TIMS_IS_VALID 护航时刻字段的正确性

摘要:本文深入解析ABAP CDS时间函数TIMS_IS_VALID的应用,重点介绍其在企业系统时间字段校验中的关键作用。文章指出无效时间数据会导致业务流程混乱,而CDS层校验能有效减少重复逻辑。详细说明TIMS类型格式要求、空值处理规则,并提供两种工程实现方案:在CDS视图中直接派生校验列,或通过ABAP SQL在内存表中批量验证。最后给出可直接运行的代码示例,包括一个ABAP报表演示内存表验证,以及一个CDS View Entity实现系统时间自动映射与校验,帮助开发者在业务场景中快速落地时间校验功能。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 194

react16的渲染过程(源码阅读总结)

最近阅读了react16.6.0的源码,写一些心得,主要是简单描述一下reactDom.render之后发生的事情,纯粹是在说是怎么实现的,一些其他收获以后再添加。 首先会根据传入的元素调用react.createElement方法传入(类型,props,子组件)创建react元素。 之后会reactDom.render会调用createContainer方法创建fiberRoot,即根节点的...

刘鹏翔的一些分享 822

Unreal5 从入门到精通之 学习Niagara特效系统

UE5 Niagara粒子系统解析 Niagara是UE5中的高性能粒子特效系统,相比传统粒子系统具有完全可编程性和可视化节点编辑两大特点。核心单元发射器(Emitter)分为模板发射器(预设效果如喷泉、火焰)和空白发射器(高度自定义)。系统提供13种预设模板,包括吹飞粒子、五彩纸屑爆发、动态光束等常见特效。 Niagara采用三级模块化设计: 系统级:全局参数设置与更新 发射器级:控制粒子生成规则与行为 粒子级:处理单个粒子的生命周期和渲染 关键模块包括初始化粒子属性、物理模拟、颜色渐变等,支持GPU加速

TxNet 1127

delphi append 怎么更新null值_小前端读源码 React组件更新原理

年后一直忙于工作,导致一直没有去继续阅读React的更新原理。今天我们接着往下阅读吧!说到更新原理就离不开setState了,React是什么时候触发组件的更新的呢?就是通过自身触发setState改变组件自身的state,或者是传入的props改变的时候触发更新组件的。之前我们都有听说过React有一个很牛逼的虚拟DOM树,能通过比对虚拟DOM树的变化去进行最小化更新组件,从而提高整个...

weixin_39962889的博客 162

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【React】617- 你真的理解setState吗?

面试官:“react中setState是同步的还是异步?”我:“异步的,setState不能立马拿到结果。”面试官:“那什么场景下是异步的,可不可能是同步,什么场景下又是同步的?”我:“...

pingan8787 336

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

你真的理解setState吗?

面试官:“react中setState是同步的还是异步?” 我:“异步的,setState不能立马拿到结果。” 面试官:“那什么场景下是异步的,可不可能是同步,什么场景下又是同步的?” 我:“......” setState真的是异步的吗? 这两天自己简单的看了下 setState 的部分实现代码,在这边给到大家一个自己个人的见解,可能文字或图片较多,没耐心的同学可以直接跳过看总结(...

栀夏暖阳的博客 395

Fix signatures do not match the previously installed version

报错信息FAILURE: Build failed with an exception.* What went wrong: Execution failed for task ':app:installDebug'. > com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: Fai

Wang的专栏 2万+

在react中 实现 base64的图片转换成formdata格式并实现上传功能

如果不想要服务端实现处理base64格式的图片的转换,那么在浏览器端来实现,部分属于伪代码,仅作为开发参考,请勿直接拷贝使用

Wang的专栏 8836

快速解决gradle下载慢的问题的小技巧

在ionic run 或build 或clean命令的时候,如果没有下载过gradle, 需要重新下载一次,而通过CLI的方式下载很慢,即使科学上网后,下载还是存在一些问题。这里总结一下,快速的下载安装方式。 步骤 本地安装 http-server 包, 通过 $ npm i -g http-server 的方式安装到全局 在官网上下载自己的版本,目前自带的版本是 2.14.1,其他版本可能在执行过

Wang的专栏 6714

React 实现 2D 画板功能

在移动端或者PC端我们来模拟画板的实现, 支持清除和导出功能,此处简单实现,仅作开发参考。 效果演示 主要代码演示 /* 此模块用于实现签名绘图功能 */ // 需要用到的变量定义 let clickX = new Array(); let clickY = new Array(); let clickDrag = new Array(); let paint; let point...

Wang的专栏 4325

React16源码: React中LegacyContext的源码实现

对于在 beginWork 中的 context 操作,可以看上述判断成立的条件下的代码,即便有符合跳过更新的操作,依然 需要 push 和 pop 操作。如果我们可以跳出组件的更新,也就是代表着当前这个 classComponent,它的state它的props都应该是没有任何变化的。对于子组件来说,它的所有子树所获取到的context肯定是经过子组件,和上层的父组件合并的 context 了, 也就是。所以,先 push 一个老的值进去再说, 然后到后面,如果发现这个组件它是要更新的,就调用这个。

Wang的专栏 2803

Fix babel-preset-react-native TransformError

错误环境新版本存在不兼容,在运行 react-native run-android 的时候,发生的错误分析: babel-preset-react-native version : @3.0.0 $ react-native -v :react-native-cli: 2.0.1 react-native: 0.47.1$node -v : v7.8.0 $ npm -v :4.4.4 解决方案

Wang的专栏 2800

React18原理: 再聊Fiber架构下的时间分片

react的任务可以被打断,其实就是基于时间分片的,人眼最高能识别的帧数不超过30帧,电影的帧数差不多是在24,浏览器的帧率一般来说是60帧,也就是每秒60个画面, 平均一个画面大概是16.5毫秒左右,浏览器正常的工作流程是运算渲染,运算,渲染运算渲染,在浏览器里面一个运算,加上一个渲染就是一帧

Wang的专栏 2796

在react项目中修改webpack中本地服务器架设的目录

一个产品的上线往往会有很多的问题,现在就出现一个需求,我们是在服务器下的某个目录进行发布,而不是根服务器,服务端不想为一个项目配置ip地址,而在react项目中,默认是走的根路径,现在我们就开始修改一下它。 前提说明 如果我们需要修改手动配置webpack, 那么根据现在的版本, 我们只能执行 npm run eject, 之后就可以着手修改了。 webpack中与需求相关的...

Wang的专栏 2397

React18源码: React调度中的3种优先级类型和Lane的位运算

可以看得出来lane&-lane的结果是SyncLane,所以通过lane&-lane就能分离出最高优先级的任务。即A(cpu)>B(IO)>C(cpu).此时的需求需要将任务B从group中分离出来,先处理cpu任务A和C。在新版本的React中,还有一个新特性,就是render阶段可能被中断,在这个期间会产生一个更高优先级的任务。如上就是通过 lanes & -lanes 分离出最高优先级的任务的,我们来看一下具体的流程。也即是说lane的代表的数值越小,此次更新的优先级就越大。

Wang的专栏 2394

React18原理: 核心包结构与两大工作循环

react中的工作循环,这是它的一个最顶层的一个流程图,在这张图里面,有两个核心的大循环,第一大循环是 react-reconciler 提供的,它的核心是构建fiber树,生成任务,第二大循环是 scheduler 提供的, 它的核心是任务调度(处理任务的优先级),react的原理实际上就是两大工作循环

Wang的专栏 2355
上一篇: React16源码: React中的异步调度scheduler模块的源码实现
下一篇: React16源码: React中的renderRoot的源码实现
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值