React18源码: reconciler执行流程

【React源码 - Fiber架构之Reconciler】 React源码-Fiber架构之Reconciler 阅读详情

reconciler执行流程


1 )概述

  • 此处先归纳一下react-reconciler包的主要作用,将主要功能分为4个方面:
    • 输入:暴露api函数(如:scheduleUpdateOnFiber), 供给其他包(如react包)调用
    • 注册调度任务:与调度中心(scheduler包)交互,注册调度任务task,等待任务回调
    • 执行任务回调:在内存中构造出fiber树,同时与渲染器(react-dom)交互,在内存中创建出与fiber对应的DOM节点
    • 输出:与渲染器(react-dom)交互,渲染DOM节点
  • 图中的1,2,3,4步骤可以反映react-reconciler包从输入到输出的运作流程
  • 这是一个固定流程,每一次更新都会运行

2 )输入

  • 在ReactFiberWorkLoop.js中,承接输入的函数只有scheduleUpdateOnFiber

  • 在 react-reconciler 对外暴露的api函数中,只要涉及到需要改变fiber的操作(无论是首次渲染或后续更新操作)

  • 最后都会间接调用 scheduleUpdateOnFiber

  • 所以scheduleUpdateOnFiber函数是输入链路中的必经之路

    //唯一接收输入信号的函数
    export function scheduleUpdateOnFiber(
      fiber: Fiber,
      lane: Lane,
      eventTime: number,
    ) {
      // ... 省略部分无关代码
      const root = markUpdateLaneFromFiberToRoot(fiber, lane);
      // 同步
      if (lane === SyncLane) {
        if (
          (executionContext & LegacyUnbatchedContext) !== NoContext &&
          (executionContext & (RenderContext | CommitContext)) === NoContext
        ) {
          // 直接进行fiber构造
          performSyncWorkOnRoot(root);
        } else {
          // 注册调度任务,经过`Scheduler'包的调度,间接进行`fiber构造'
          ensureRootIsScheduled(root, eventTime);
        }
      } else {
        // 注册调度任务,经过`Scheduler`包的调度,间接进行`fiber构造`
        ensureRootIsScheduled(root, eventTime);
      }
    }
    
  • 逻辑进入到scheduleUpdateOnFiber之后,后面有2种可能:

    • 1.不经过调度,直接进行fiber构造.
    • 2.注册调度任务,经过Scheduler包的调度,间接进行fiber构造.

2 )注册调度任务

与输入环节紧密相连,scheduleUpdateOnFiber函数之后,立即进入 ensureRootIsScheduled 函数

// ... 省略部分无关代码
function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
  //前半部分:判断是否需要注册新的调度
  const existingCallbackNode - root. callbackNode;
  const nextlanes = getNextLanes(
    root,
    root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
  );
  const newCallbackPriority = returnNextLanesPriority();
  if (nextLanes === NoLanes) {
    return;
  }
  if (existingCallbackNode !== null) {
    const existingCallbackPriority = root.callbackPriority;
    if (existingCallbackPriority === newCallbackPriority) {
      return;
    }
    cancelCallback(existingCallbackNode);
  }
  // 后半部分:注册调度任务
  let newCallbackNode;
  if (newCallbackPriority === SyncLanePriority){
    newCallbackNode = scheduleSyncCallback(
      performSyncWorkOnRoot.bind(null, root),
    );
  } else if (newCallbackPriority === SyncBatchedLanePriority) {
    newCallbackNode = scheduleCallback(
      ImmediateSchedulerPriority,
      performSyncWorkOnRoot.bind(null, root),
    );
  } else {
    const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
      newCallbackPriority,
    );
    newCallbackNode = scheduleCallback(
      schedulerPriorityLevel,
      performConcurrentWorkOnRoot.bind(null, root),
    );
  }
  root.callbackPriority = newCallbackPriority;
  root.callbackNode = newCallbackNode;
}
  • ensureRootIsScheduled的逻辑很清晰,分为2部分:
    • 1.前半部分:判断是否需要注册新的调度(如果无需新的调度,会退出函数)
    • 2.后半部分:注册调度任务
      • performSyncWorkOnRoot 或 performConcurrentWorkOnRoot 被封装到了任务回调 (schedulecallback)
      • 等待调度中心执行任务,任务运行其实就是执行 performSyncWorkOnRoot 或 performConcurrentWorkOnRoot

3 )执行任务回调

  • 任务回调,实陈上就是执行 performSyncWorkOnRoot 或 performConcurrentWorkOnRoot

  • 简单看一下它们的源码将主要逻辑剥离出来,单个函数的代码量并不多

    //..,省略部分无关代码
    function performSyncWorkOnRoot(root) {
      let lanes;
      let exitStatus;
    
      lanes = getNextLanes(root, NoLanes);
      // 1. fiber树构造
      exitStatus = renderRootSync(root, lanes);
    
      // 2. 异常处理:有可能fiber构造过程中出现异常
      if (root.tag !== LegacyRoot && exitStatus === RootErrored) {
        // ...
      }
    
      // 3. 输出:渲染fiber树
      const finishedWork: Fiber = (root.current.alternate: any);
      root.finishedwork = finishedWork;
      root.finishedLanes = lanes;
      commitRoot(root);
    
      // 退出前再次检测,是否还有其他更新,是否需要发起新调度
      ensureRootIsScheduled(root, now());
      return null;
    }
    
  • performSyncWorkOnRoot 的逻辑很清晰,分为3部分:

    • fiber 树构造

    • 异常处理: 有可能fiber构造过程中出现异常

    • 调用输出

      // ... 省略部分无关代码
      function performConcurrentWorkOnRoot(root) {
        const originalCallbackNode = root.callbackNode;
      
        // 1、刷新pending状态的effects,有可能某些effect会取消本次任务
        const didFlushPassiveEffects = flushPassiveEffects();
        if (didFlushPassiveEffects) {
          if (root.callbackNode !== originalCallbackNode) {
            // 任务被取消,退出调用
            return null;
          } else {
            // Current task was not canceled. Continue.
          }
        }
      
        // 2.获取本次渲染的优先级
        let lanes = getNextLanes(
          root,
          root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
        );
      
        // 3.构造fiber树
        let exitStatus = renderRootConcurrent(root, lanes);
        if (
          includesSomeLane(
            workInProgressRootIncludedLanes,
            workInProgressRootUpdatedLanes,
          )
        ) {
          // 如果在render过程中产生了新的update,且新update的优先级与最初render的优先级有交集
          // 那么最初render无效,丢弃最初render的结果,等待下一次调度
          prepareFreshStack(root, NoLanes);
        } else if (exitStatus !== RootIncomplete) {
          // 4、异常处理:有可能fiber构造过程中出现异常
          if (exitStatus == RootErrored) {
            // ...
          }
          const finishedWork: Fiber = (root.current. alternate: any);
          root.finishedWork = finishedwork;
          root.finishedLanes = lanes;
          // 5.输出:渲染fiber树
          finishConcurrentRender(root, exitStatus, lanes);
        }
      
        // 退出前再次检测,是否还有其他更新,是否需要发起新调度
        ensureRootIsScheduled(root, now());
        if (root.callbackNode === originalCallbackNode) {
          // 渲染被阻断,返回一个新的performConcurrentWorkOnRoot函数。等待下一次调用
          return performConcurrentWorkOnRoot.bind(null, root);
        }
        return null;
      }
      
  • performConcurrentWorkOnRoot 的逻辑与 performSyncWorkOnRoot 的不同之处在于

  • 对于可中断渲染的支持:

    • 1.调用 performConcurrentWorkOnRoot 函数时,首先检查是否处于 render 过程中,是否需要恢复上一次渲染
    • 2.如果本次渲染被中断,最后返回一个新的 performConcurrentWorkOnRoot 函数,等待下一次调用

4 )输出

// ... 省略部分无关代码
function commitRootImpl(root, renderPriorityLevel) {
  // 设置局部变量
  const finishedWork = root.finishedWork;
  const lanes - root. finishedLanes;

  // 清空FiberRoot对象上的属性
  root.finishedWork = null;
  root.finishedLanes = NoLanes;
  root.callbackNode = null;
  
  // 提交阶段
  let firstEffect = finishedWork.firstEffect;
  if (firstEffect !== null) {
    const prevExecutionContext - executionContext;
    executionContext |= CommitContext;
    // 阶段1:dom突变之前
    nextEffect = firstEffect;
    do {
      commitBeforeMutationEffects();
    } while (nextEffect !== null);

    // 阶段2:dom突变,界面发生改变
    nextEffect = firstEffect;
    do {
      commitMutationEffects(root, renderPriorityLevel);
    } while (nextEffect !== null);
    root.current = finishedWork;
    
    // 阶段3:layout阶段,调用生命周期componentDidUpdate和回调函数等
    nextEffect = firstEffect;
    do{
      commitLayoutEffects(root, lanes);
    } while (nextEffect !== null);
    nextEffect = null;
    executionContext = prevExecutionContext;
  }
  ensureRootIsScheduled(root, now());
  return null;
}
  • 在输出阶段,commitRoot 的实现逻辑是在 commitRootImpl 函数中
  • 其主要逻辑是处理副作用队列,将最新的fiber树结构反映到DOM上
  • 核心逻辑分为3个步骤:
    • 1.commitBeforeMutationEffects
      • dom变更之前,主要处理副作用队列中带有Snapshot, Passive标记的fiber节点
    • 2.commitMutationEffects
      • dom变更,界面得到更新.主要处理副作用队列中带有
      • Placement,Update,Deletion, Hydrating标记的fiber节点
    • 3.commitLayoutEffects
      • dom变更后,主要处理副作用队列中带有 update | Callback 标记的fiber节点.
  • 这块流程参考 React16版本的流程,看下不同之处
  • 所以,整个 reconciler 的执行过程中,核心做了2个事情
    • 1 )Render (基于task, 可以被打断, 可以被打断的前提是基于渲染 mode)
      • 初始化 fiber
      • 更新 fiber
    • 2 )commit
      • dom 变更之前
      • dom 变更
      • dom 更新之后
React 调和(Reconciler)原理理解 文章目录FiberFiber 更新机制 Fiber Reactv15及之前,React 对于虚拟 DOM 是采用 递归方式 遍历更新的,一次更新,从应用根部递归更新,递归开始后中途无法终端,随着项目复杂,层级变深,导致更新时间变成,给前端交互上的体验就卡顿。 Fiber 诞生在 Reactv16 版本,Fiber 架构目的就是解决大型 React 应用卡顿,fiber 在 React 中是最小粒度的执行单元,在遍历更新每一个节点的时候都不是用的真实 DOM ,都是采用虚拟 DOM ,所以可以 理解成 f 阅读详情

相关推荐

React 18 源码解读(一)

本文深入解析了React源码架构及核心实现原理。首先介绍了React采用Monorepo架构管理,详细拆解了react(基础包)、react-dom(Web渲染器)、react-reconciler(协调器)、scheduler(调度器)等核心包的职责分工。其次通过Babel示例分析了JSX编译过程,将JSX转换为React.createElement调用。然后重点剖析了React的双阶段工作流程:创建阶段完成容器初始化,更新阶段处理状态变更和视图更新。

分享前端工程化、AI 应用、Agent 开发与大模型实践! 819

【React】react-reconciler快速入门

前言 我最近在研究新版taro的原理,其中就有使用该库制作自定义渲染器。一起学习下吧。 老版taro原理到时候会专门写个文章手写下。已经整理完成。 react-reconciler 这个是react抽离的协调器逻辑,用于编写自定义渲染器。 https://www.npmjs.com/package/react-reconciler const Reconciler = require('react-reconciler'); const HostConfig = { // You'll nee

不忘初心,坚定道路! 2801

react源码解析3.react源码架构

react源码解析3.react源码架构 视频讲解(高效学习):进入学习 往期文章: 1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录结构和调试 5.jsx&核心api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.

weixin_59558923的博客 1007

【从0实现React18】 (三) 初探reconciler 带你初步探寻React的核心逻辑

Reconciler使React核心逻辑所在的模块,中文名叫,协调(reconciler)就是的意思。

m0_74989367的博客 1330

react源码:目录结构、调试源码

我的技术栈是React,最近在整理react的源码,react版本是18.1.0,之前版本,没有看过,就此略过。

读心悦 1476

react-使用reactreconciler实现一个微型dom

使用react-reconciler实现一个微型dom

react源码分析(14)-react-reconciler分析总结以及从宏观层面看待react

目录 2021SC@SDUSC react-reconciler图示(推荐打开下方链接,查看清晰原图) react-reconciler中流程总结(与组件更新为例) 代码外的小插曲(开源协议) react与vue的比较 react中的热点 hooks react18的未来特性 总结 2021SC@SDUSC react-reconciler图示(推荐打开下方链接,查看清晰原图) 这是我分析的对react-reconciler部分运行的整体介绍图,因为图片太大,这里附加URL..

weixin_45668912的博客 991

永磁同步电机自抗扰控制ADRC(位置环/速度环控制器)Matlab/Simulink仿真(S-Function)

ESO是ADRC的核心,其作用是跟踪被控对象的输出,同时给出受控对象的各阶状态变量以及系统总扰动的实时估计,将其补偿到控制器中,实现动态补偿线性化。NLSEF采用非线性函数把TD产生的跟踪及微分信号与ESO给出的状态变量估计值之间的误差进行非线性组合得到初级控制量,然后同总扰动的补偿量一起生成最终的控制信号。自抗扰控制(ADRC)技术的核心思想是将简单的积分串联型视为标准模型,把系统模型中不同于标准型的部分和外部干扰之和视为总扰动,并将其扩张为一个新的状态。看作系统内外部扰动之和。令一个高阶状态变量为。

m0_66341377的博客 7615

React18源码: React中的LanePriority和SchedulerPriority

reactPriorityLevel, 属于react-reconciler包,定义于 SchedulerWithReactIntegration.js中。与fiber构造过程相关的优先级(如fiber.updateQueue,fiber.lanes)都使用LanePriority.为了能协同调度中心(scheduler 包) 和 fiber树构造(react-reconciler包)中对优先级的使用。由于本节重点介绍优先级体系以及它们的转换关系,关于Lane(车道模型)在fiber树构造时使用。

Wang的专栏 1626

【JESD79-5之】11 IDD, IDDQ, IPP规格参数和测试条件(IDD, IDDQ, IPP Specification Parameters and Test conditions)

【代码】【JESD79-5之】11 IDD, IDDQ, IPP规格参数和测试条件(IDD, IDDQ, IPP Specification Parameters and Test conditions)

m0_61126667的博客 4863

用FPGA在HDMI上显示自定义字符:从COE文件到OSD叠加的保姆级教程

本文详细介绍了如何在FPGA上实现HDMI视频流的OSD字符叠加技术,从COE文件生成到动态区域控制的完整流程。通过Verilog代码示例和实战技巧,帮助开发者掌握字符ROM设计、像素坐标追踪和动态混合等核心技术,适用于视频监控、系统状态显示等应用场景。

weixin_28720767的博客 231

(万字长文)React 18 源码与原理解读 —— 看这一篇就够了

本节是整个React 的源码与原理解读解读教程的最后一章,作者会用自己的理解带着大家梳理一下整个 React 的运行过程,因为篇幅的问题,作者会主要讲述一下一下重点的内容和要点的信息,侧重给读者一个完整的运行逻辑,对于讲解不到位的部分可以阅读之前的详细教程,教程肯定还是会有疏漏的部分请大家海涵

weixin_46463785的博客 7355

恶意代码实验3:Word宏病毒实验

只要下次打开这个word文档,就会执行以上代码,并将自身复制到Normal.dot(word文档的公共模板)和当前文档的ThisDocument中,同时改变函数名(模板中为Document_Close,当前文档为Document_Open),此时所有的word文档打开和关闭时,都将运行以上的病毒代码,可以加入适当的恶意代码,影响word的正常使用,本例中只是简单的跳出一个提示框。回答不正确三次,即可自动跳出病毒程序,但那时已经出现几十个文档。1、打开的宏编辑器如图所示,即可编写病毒代码。

qq_63949327的博客 6506

React18源码: schedule任务调度messageChannel

看完这8个内部函数,最后浏览一下完整的 performWorkUntilDeadline 回调的实现。调度中心最核心的代码,在 SchedulerHostConfig.default.js 中。这4个函数代码都很简洁,其功能在注释中都有解释.1 )调度相关:请求或取消调度。

Wang的专栏 1843

金蝶云星空核心数据表解析与高效关联查询指南

本文深入解析金蝶云星空核心数据表结构,提供高效关联查询的实战指南。文章详细介绍了基础资料、业务单据和财务模块的关键表及其关联逻辑,重点阐述了如何利用关联表(_LK表)进行跨单据溯源,并分享了编写高性能SQL的实用技巧与避坑建议,帮助开发者、实施顾问和数据分析师快速掌握数据查询方法,提升工作效率。

weixin_29254673的博客 526

基于MATLAB的拉盖尔-高斯光束叠加相位模拟

首先,我们需要设置模拟所需的参数,如光腰半径、传播距离、光束的角动量等。其中,(U)表示光束的电场复振幅,(r)和(\phi)分别是极坐标系下的径向和角向坐标,(z)是传播距离,(A)是归一化系数,(w_p)是光束的光腰半径,(L_p^q)是拉盖尔多项式,(k)是波数,(l)是光束的角动量。通过修改模拟参数,如光腰半径、传播距离、角动量等,您可以进一步探索和理解拉盖尔-高斯光束的叠加相位效应。拉盖尔-高斯光束是一种特殊的光束模式,具有广泛的应用领域,包括光学信息处理、激光加工和量子光学等。

m0_47037246的博客 945

React核心源码解析

本文对比 React15,以及16.8之后的版本来对 React 核心源码进行解析,包含fiber、双缓存、JSX编译、diff算法等内容。

musio777的博客 1822

基于YOLOv5/v8/v10的答题卡填涂识别与评分系统(附数据集+UI界面+完整代码)

在教育信息化的大背景下,传统的手工阅卷方式正在被智能化技术所取代。答题卡识别作为标准化考试的核心环节,其准确率和效率至关重要。本文将详细介绍如何利用YOLO系列目标检测算法(YOLOv5、YOLOv8、YOLOv10)构建一个答题卡填涂识别与评分系统。文章从数据集的制作与标注开始,逐步深入到模型的训练、评估与对比,最后基于PyQt5设计了一个用户友好的桌面端UI界面,实现了从图像输入到得分输出的全流程自动化。

YOLO 640

react源码从入门到入定

1、执行performUnitOfWork2、workInProgress有child -->执行 beginWork(构建当前节点 以及节点的子节点的child和sibings指针)3、workInProgress无child 有sibings -> 执行completeWork(构建当前节点的dom & append子节点的dom)

星海拾遗 1008

第二篇:APS智能排产实战:OR-Tools与coptpy从入门到案例

专注于具体的技术实现,包括 OR-Tools 和 coptpy 的详细使用指南、建模技巧、日志解读,以及一个完整的两阶段生产排程案例。适合准备动手开发 APS 系统的工程师和研究者。

算法工程师 455

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

上一篇: React18原理: React核心对象之Update、UpdateQueue、Hook、Task对象
下一篇: React18源码: reconcliler启动过程
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、付费专栏及课程。

余额充值