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分析 的相关文章

  • 未捕获的引用错误:i 未定义

    我正在尝试在我的数组上创建一个 for 循环 var lists a b c d JS for i 0 i lt lists length i console log lists i sa report btn lists i click
  • JSON字符串转JS对象

    我正在使用 JS 对象通过 Google 可视化创建图表 我正在尝试设计数据源 首先 我在客户端创建了一个 JS 对象 var JSONObject cols id date label Date type date id soldpenc
  • 在 Cypress 中提取部分文本

    我是 Cypress 的新手 我需要从我的应用程序中提取文本的动态部分 div Hello World greeting number 9123 div 在此示例中 我需要从 div 中提取 9123 以便稍后在测试中使用 知道我应该怎么做
  • react-dom/server 可以在客户端工作吗?

    我需要在客户端呈现顶级 html 标签 例如 结果将被注入到 iframe 中 在服务器上 我会使用renderToStaticMarkup函数来自react dom server 但仅限客户端react dom没有这个功能 Will re
  • 链接 getElementById

    我一直在寻找这个问题的答案 但找不到答案 所以我想尝试一下 StackOverflow 在 javascript 中 这是否有效 x document getElementById myId y x getElementById mySec
  • 为什么我无法使用 HTML5 音频标签多次播放声音?

    这就是声音的 存储 方式
  • d3 树 - 有相同孩子的父母

    我一直在将代码从 JIT 转换为 D3 并使用树布局 我已经复制了代码http mbostock github com d3 talk 20111018 tree html http mbostock github com d3 talk
  • 在生产中使用 css / javascript 源映射对性能有何影响?

    生产环境中应该使用源映射吗 除了调试之外 它们还有什么好处吗 由于额外的服务器往返 它们是否会影响应用程序加载时间 浏览器是否足够智能来加载 map应用程序加载和渲染后的资产 如果浏览器找不到 map asset 404错误 会对性能产生影
  • 如何在D3节点中放置图像?

    到目前为止 我已经创建了这些 D3 节点 用于创建可折叠的层次树 到目前为止 这些节点的颜色为 AA1C1C 深红色 以表明如果您单击它们 它们将扩展到更多节点 我想要做的是在节点中使用图像中的位置 这对于所有用户来说都是一个加号 以知道它
  • 仅当 url 以 www 为前缀时才会发生 CORS 错误

    我目前遇到一个关于 CORS 跨源资源共享 的问题 奇怪的是 只有当我使用 www url 前缀时 才会出现这种情况 例如 当我使用以下网址访问我的网站时 http example com index http example com in
  • 按住鼠标时 JavaScript 重复动作

    是否有一个 JavaScript 函数每隔如此多的毫秒重复一次 以至于按住 html 按钮 如果这可以使用标准 JavaScript 来完成 那就太好了 但使用 jQuery 或 jQuery 插件也很棒 On the mousedown
  • 匹配CSS的正则表达式“<属性>:<值>”

    我从以下位置检索了 CSS 规则document styleSheets现在我正在寻找提取它的属性和值 cssText expl position absolute background color rgb 204 204 204 max
  • 单击元素外部时触发事件的指令

    我知道有很多问题都在问类似的事情 但没有人真正解决我的问题 我正在尝试构建一个指令 当鼠标单击当前元素外部时 该指令将执行表达式 为什么我需要这个功能 我正在构建一个应用程序 在这个应用程序中 有 3 个下拉菜单 5 个下拉列表 如选择的
  • 如何按日期升序对对象进行排序?

    如果我有一个对象列表 var objectList LIST OF OBJECT each object列表中包含三个属性 name date gender 如何按 对列表中的对象进行排序date 属性升序 the date 属性包含字符串
  • jQuery 删除函数真的删除 Dom 元素吗?

    我真的想知道 jQuery 是否remove http api jquery com remove 函数确实从 DOM 中删除元素 首先 我看了here https stackoverflow com questions 2185760 j
  • 使用Doctype让scrollTop返回0,为什么?

    当我将此 Doctype 放入我的文档中时document body scrollTop返回零 这是为什么 当您使用该 Doctype 时 您会将每个当前浏览器放入所谓的几乎标准模式 http hsivonen iki fi doctype
  • bootstrap-datetimepicker 仅显示日期

    我正在用这个repo https github com smalot bootstrap datetimepicker由 smalot 提供 我只想选择并显示日期 对于其他一些地方 我显示数据和时间 因此选择此存储库 我可以设法仅使用它来选
  • 如何控制谷歌地图标记的不透明度

    我需要根据时间使一些标记半透明 有什么方法可以控制标记的 CSS 不透明度吗 或者是否可以可靠地找出标记的 DOM 元素 我使用 Google 地图 API v3 标记的不透明度可以设置为marker setOptions opacity
  • 如何选中表格中输入文本焦点上的复选框

    我试图在输入文本焦点上检查表 DOM 中的复选框 但无法访问复选框元素 但我的焦点正在工作 这是我的 jsfiddle 链接https jsfiddle net 9qha9vft https jsfiddle net 9qha9vft 这是
  • 如何从 vue 组件调用 App.vue 中的方法

    我有一个 vue 组件和一个 vue 元素声明 如下所示 Vue component todo item template li This is a todo li methods test function I am getting an

随机推荐

  • 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