React源码分析(一)=> scheduler分析

2023-11-06

1. 前言

为了读代码更加有效率,提前看了一篇如何阅读源码的文章:https://zxc0328.github.io/2018/05/01/react-source-reading-howto/
因此此次本人阅读源码主要想看懂以下6个问题:

  1. ReactDOM.render()是如何挂载到真实DOM上的
  2. setState实现原理,为什么是异步的
  3. 生命周期结合2号问题一起看
  4. react16的fiber架构是什么
  5. jsx是如何解析的
  6. react hook是如何做到的

分析代码基于React V16.8.6,react源码目录截图如下图所示:
在这里插入图片描述

所需要看的代码一个库就够了,https://github.com/facebook/react/


先看的react-dom代码, 一点点单步到了scheduler, 这个包的代码看起来不多(可能是我第一次看框架源码, 看的有点恶心… 一堆全局变量, 各个函数来回调用, 看了好几天, 如果下面哪里有问题, 还请各位同行指点), 那就先来梳理下这个包吧.

scheduler这个包主要是在react做diff做任务分配机制, 核心机制类似于requestidlecallback,

window.requestIdleCallback()会在浏览器空闲时期依次调用函数, 这就可以让开发者在主事件循环中执行后台或低优先级的任务,而且不会对像动画和用户交互这样延迟敏感的事件产生影响。

但这个函数支持度太惨
在这里插入图片描述
react则使用requestAnimationFramepostMessage来模拟实现的requestidlecallback. 工作原理是调度requestAnimationFrame,存储帧开始的时间,然后调度postMessage,后者在绘制后进行调度。

该包主要流程是把所有任务通过双向链表连接起来, 通过requestAnimationFrame来在浏览器每帧的空闲时间循环处理所有任务, 直到链表为空为止.


2. getCurrentTime

这个函数后面会经常用到的, 先到前面来说下, 先看代码:

// packages\scheduler\src\forks\SchedulerHostConfig.default.js
const hasNativePerformanceNow =
  typeof performance === 'object' && typeof performance.now === 'function';
const localDate = Date;

if (hasNativePerformanceNow) {
   
  const Performance = performance;
  getCurrentTime = function() {
   
    return Performance.now();
  };
} else {
   
  getCurrentTime = function() {
   
    // 该方法在 ECMA-262 第五版中被标准化, Date.now() === new Date().getTime();
    // 出处 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
    return localDate.now();
  };
}

performance.now()Date.now() 不同的是,返回了以微秒(百万分之一秒)为单位的时间,更加精准。

并且与 Date.now() 会受系统程序执行阻塞的影响不同,performance.now() 的时间是以恒定速率递增的,不受系统时间的影响(系统时间可被人为或软件调整)。

注意Date.now()输出的是 UNIX 时间,即距离 1970 的时间,而performance.now()输出的是相对于 time origin(页面初始化: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#The_time_origin) 的时间。

使用 Date.now() 的差值并非绝对精确,因为计算时间时受系统限制(可能阻塞)。但使用 performance.now() 的差值,并不影响我们计算程序执行的精确时间。

3. unstable_scheduleCallback函数

  • 函数前面的unstable表示不稳定的意思, 之后还会有变动.
  • 这个方法主要就是将任务组成双向链表, 并按照过期时间作为优先级.

先定义优先级, 代码如下:

// packages\scheduler\src\Scheduler.js

// Max 31 bit integer. The max integer size in V8 for 32-bit systems.
// 这是32位系统V8引擎里最大的整数
// Math.pow(2, 30) - 1
// 0b111111111111111111111111111111
var maxSigned31BitInt = 1073741823;
// Times out immediately 立即过期
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
// Eventually times out
var USER_BLOCKING_PRIORITY = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
// Never times out
var IDLE_PRIORITY = maxSigned31BitInt;

主函数代码如下:

// packages\scheduler\src\Scheduler.js

// 组成双向链表, 开始安排任务
function unstable_scheduleCallback(priorityLevel,  callback,  deprecated_options) {
   
  var startTime =
    currentEventStartTime !== -1 ? currentEventStartTime : getCurrentTime();

  // 过期时间 = 加入时间 + 优先级时间
  var expirationTime;
  if (
    typeof deprecated_options === 'object' &&
    deprecated_options !== null &&
    typeof deprecated_options.timeout === 'number'
  ) {
   
    expirationTime = startTime + deprecated_options.timeout;
  } else {
   
    // 根据不同的优先级, 赋予不同的过期时间
    switch (priorityLevel) {
   
      case ImmediatePriority:
        expirationTime = startTime + IMMEDIATE_PRIORITY_TIMEOUT;
        break;
      case UserBlockingPriority:
        expirationTime = startTime + USER_BLOCKING_PRIORITY;
        break;
      case IdlePriority:
        expirationTime = startTime + IDLE_PRIORITY;
        break;
      case LowPriority:
        expirationTime = startTime + LOW_PRIORITY_TIMEOUT;
        break;
      case NormalPriority:
      default:
        expirationTime = startTime + NORMAL_PRIORITY_TIMEOUT;
    }
  }
  
// 未完

上面先计算一下callback的过期时间, 接下来创建链表节点, 并组成链表, 代码如下:

// packages\scheduler\src\Scheduler.js

// 续上
// 基于上面的优先级和过期时间创建一个节点
var newNode = {
   
    callback,
    priorityLevel: priorityLevel,
    expirationTime,
    next: null,
    previous: null,
  };

  if (firstCallbackNode === null) {
   
    // This is the first callback in the list. 如果firstCallbackNode没有, 说明是第一个节点
    firstCallbackNode 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React源码分析(一)=> scheduler分析 的相关文章

  • 将 HTML 表格结构复制到剪贴板

    我只是在寻找这方面的建议 我一直在互联网上寻找可能的解决方案 了解如何将 HTML 表格结构及其文本复制到剪贴板 但到目前为止还没有那么幸运 我现在拥有的是一个包含数据的简单表格 用户需要在复制 粘贴时使用 Outlook 将其复制到电子邮
  • 在 Firefox 中访问全局事件对象

    目标 运行一些函数 ajaxStart 但仅限于由特定事件触发时 代码 loading indicator ajaxStart function if event null if event type hashchange event ty
  • 具有动态过滤标准的 JS Array.filter

    如何动态声明一组过滤条件而无需指定过滤器的数量 例如 如果我有一组数据 如下所示 var data item type wood size 10 item type wood size 8 item type metal size 8 我知
  • Document.createElement("br") 不适用于多次调用appendChild

    HTML var x document createElement p var br1 document createElement br var br2 document createElement br var t5 document
  • Firefox 中的 jQuery 表单提交

    请帮我解决一个问题 我有这个代码 用于通过锚点提交表单
  • ngRepeat 中的函数执行过于频繁

    我有三个tabs里面有不同的htmlng include 这些选项卡使用以下方式显示ng repeat 只有一个 HTML 模板包含函数调用 但它执行了 3 次 每个模板执行一次 ng repeat迭代 这里出了什么问题以及如何解决它 va
  • Xhr上传event.loaded问题

    opts xhr function var xhr new window XMLHttpRequest Upload progress xhr upload onprogress function e if e lengthComputab
  • jQuery Mobile:$(...).listview 不是函数

    我正在尝试在 UL 中动态插入 LI 元素后刷新 jQuery Mobile 中的列表视图 每当我尝试 myUL listview refresh 在控制台上我收到错误 未捕获的类型错误 listview 不是函数 我该如何解决这个问题 确
  • 如何从客户端设置 HTMLEditorExtender HTML

    我无法让它工作 这是我在另一个线程中找到的代码 但它对我不起作用 我得到 set content 不是函数 find set content whatever 这仍然有效吗 我还尝试设置它扩展的文本框的值 尝试设置两者的 InnerHtml
  • Scalatest PlusPlay Selenium 无法调整窗口大小

    对此已经研究了一段时间 我似乎找不到使用 scalatest plus 调整窗口大小的方法 我发现在线搜索或文档的唯一方法http doc scalatest org 2 1 5 index html org scalatest selen
  • Javascript - window.getCompulatedStyle 返回“auto”作为元素顶部和左侧属性

    在我的网页上 我有一些元素 div 子 div 按钮等 其位置是相对于它们所在的 div 以及彼此之间生成的 这会导致使用时的结果window getCompatedStyle the top and left属性不是数字值 而是简单的 a
  • 等待两个异步函数完成,然后在 Node.js 中继续

    我正在 Node js 中开发一个应用程序 其中调用异步函数两次 并将值分配给全局变量 问题是我想使用这两个调用的结果来做其他事情 但是这个其他事情不会等待结果被分配 这是我的代码 var a var b let x abcd foo x
  • Elasticsearch 前缀匹配消失且未添加 (QueryString)

    结转自Elasticsearch QueryStrings 部分匹配 NOT 查询 https stackoverflow com questions 40100006 elasticsearch querystrings partiall
  • 点击事件的事件处理程序自动触发 - jQuery [重复]

    这个问题在这里已经有答案了 可能的重复 为什么单击事件处理程序会在页面加载后立即触发 https stackoverflow com questions 7102413 why does click event handler fire i
  • React:在哪里扩展对象原型

    我使用创建了一个纯 React 应用程序创建反应应用程序 https github com facebookincubator create react app 我想延长String类并在一个或多个组件中使用它 例如 String prot
  • 返回不在函数中

    Firebug 报告 返回不在函数中 错误 没有位置 好吧 第 1 行什么都没有 我怎样才能找到这个错误的根源 return not in function Break on this error return 0 javascript r
  • Magnific Popup:来自span的源标题

    我想从锚标记内的隐藏标题字段中获取放大图像的标题 而不是从标题中获取 这是因为我的标题包含标记 HTML a href img zoom jpg img src img small jpg alt span class hide This
  • 在 jQuery 中获取最接近元素的形式

    我编写了这个 js jquery 脚本来检查表单中的所有复选框 它工作得很好 但是这会检查页面上的所有复选框 无论它们是什么表单包装器 这是函数 function toggleCheck state var checkboxes jQuer
  • 嵌套对象的 setState

    我有一个嵌套对象作为状态 并且在组件中有一个表单 我正在考虑每次用户在表单中输入某些内容时更新状态 并且为了避免为每个输入创建许多函数 我正在考虑使用 switch 创建单个函数 使用 switch 创建单一函数是个好主意吗 如何更新对象的
  • 只允许在输入字段中输入数字

    我想要打开电话号码字段这个网站 http myfrugaltech com dev savoo register 只接受数字或数字 我无权编辑 HTML 代码 那么可以使用 jQuery 通过定位字段 ID 来完成此操作吗 如果可以的话 该

随机推荐

  • AI Studio 飞桨 零基础入门深度学习笔记2-基于Python编写完成房价预测任务的神经网络模型

    AI Studio 飞桨 零基础入门深度学习笔记2 基于Python编写完成房价预测任务的神经网络模型 波士顿房价预测任务 线性回归模型 线性回归模型的神经网络结构 构建波士顿房价预测任务的神经网络模型 1 数据处理 1 1 读入数据 1
  • 企业订单管理软件

    企业订单管理软件 网上订货宝APP系统功能介绍 一 系统概述和用途 系统基于网络 实现厂家和代理商批发商通过网络下单订货功能 二 解决问题 1 解决订单管理混乱问题 2 解决订单遗漏问题 3 解决订单欠款遗漏问题 4 解决不同客户不同价格管
  • 在Windows下使用Python嵌入式环境包

    在 Python Releases for Windows 页面下载你需要的那个版本的 Windows embeddable package 64 bit 文件 这样就得到一个 python x x x embed amd64 zip 文件
  • Hash算法的使用

    Hash算法的使用 标签 默认分类 发表时间 2011 08 06 06 35 作者 GliderX khsing 分享到 出处 http hi baidu com gliderx 在对语料文本进行2 3元切分时 需要借助hash表来获得切
  • 信息学奥赛一本通 1170:计算2的N次方

    题目链接 http ybt ssoier cn 8088 problem show php pid 1170 思路 计算 2 2 2 的 n n n 次方相当于大整数 1
  • 目标检测-yolov50-火灾识别可视化

    使用yolov5模型对利用开源火灾数据集进行训练模型 实现对照片 视频以及摄像头的火焰烟雾的检测 详细的环境配置见 目标检测 YOLOV5 口罩检测 学习目标 数据集的准备 预训练权重 训练模型 训练模型路径的修改 模型测试 pyqt可视化
  • 完整代码CNN-LSTM多变量时间序列预测

    import torch from torch import nn import pandas as pd import numpy as np import matplotlib pyplot as plt from sklearn pr
  • vue源码解析---AST抽象语法树

    目录 首先AST是什么 指针思想 递归深入 斐波那契数列 递归深入 形式转换 栈结构 AST语法树 首先AST是什么 在计算机科学中 抽象 语法树 abstract syntax tree或者缩写为AST 或者语法树 syntax tree
  • Finding a needle in Haystack: Facebook’s photo storage

    文章目录 Finding a needle in Haystack Facebook s photo storage 简介 背景 设计细节 Haystack Directory Haystack Cache Haystack Store 优
  • QWidget、QDialog及QMainWindow的区别与联系

    QWidget类是所有用户界面对象的基类 QMainWindow和QDialog都是QWidget的子类 一般来说 如果需要嵌入到其他窗体中 则基于QWidget创建 如果是顶级对话框 则基于QDialog创建 如果是主窗体 则基于QMai
  • H5如何直接跳转小程序?

    1 云开发方式 不推荐 不推荐理由 1 要钱 2 麻烦 需要兼容 参考链接 https developers weixin qq com miniprogram dev wxcloud guide staticstorage jump mi
  • 稀疏重构算法详解

    引入 在室内环境中 多径信号具有天然的空间稀疏性 根据压缩感知理论可知 如果信号是可压缩的或者在某个变换域是稀疏的 可以采用一个随机测量矩阵将高维信号映射到一个低维空间上 通过求解优化问题 以很高的概率重构出原始信号 因此 在该理论框架下
  • 带分数

    标题 带分数 100 可以表示为带分数的形式 100 3 69258 714 还可以表示为 100 82 3546 197 注意特征 带分数中 数字1 9分别出现且只出现一次 不包含0 类似这样的带分数 100 有 11 种表示法 题目要求
  • 小心踩雷,一次Java内存泄漏排查实战

    问题出现 晚上七点多开始 我就开始不停地收到报警邮件 邮件显示探测的几个接口有超时情况 多数执行栈都在 java io BufferedReader readLine BufferReader java 389 java io Buffer
  • c++ 变量常量指针练习题

    Q1 在win32 x86模式下 int p int pp double q 请说明p pp q各占几个字节的内存单元 p 占 4 个字节 pp 占 4 个字节 q 占 4 个字节 Q2常量1 1 0 1 的数据类型是什么 1 是 整形 i
  • YOLOv7中的数据集处理【代码分析】

    本文章主要是针对yolov7中数据集处理部分代码进行解析 和yolov5是一样的 也是可以更好的理解训练中送入的数据集到底是什么样子的 数据集的处理离不开两个类 一个是Dataset from torch utils data import
  • python3 -sorted函数 对所有可迭代的对象进行排序操作 sorted(corr_list,key=lambda x: -abs(x[0]))

    sorted 函数对所有可迭代的对象进行排序操作 返回重新排序的列表 sort 与 sorted 区别 sort 是应用在 list 上的方法 sorted 可以对所有可迭代的对象进行排序操 作 list 的 sort 方法返回的是对已经存
  • linux export 的作用

    功能说明 设置或显示环境变量 语 法 export fnp 变量名称 变量设置值 补充说明 在shell中执行程序时 shell会提供一组环境变量 export可新增 修改或删除环境变量 供后续执行的程序使用 export的效力仅及于该此登
  • 我在腾讯做测10年,总结的7条生存经验

    简单做个自我介绍 我是一名测试工程师 从15年毕业到现在工作了6年 一路走过来 觉得自己很幸运遇到了很多伯乐 教会了我很多道理和职场经验 也非常荣幸在阿里工作过4年 搭建过蚂蚁金服的platuo测试框架 thrift测试框架 自动化测试平台
  • React源码分析(一)=> scheduler分析

    文章目录 1 前言 2 getCurrentTime 3 unstable scheduleCallback函数 4 scheduleHostCallbackIfNeeded 4 1 flushWork 4 2 flushFirstCall