React 原理分析

优质博文:IT-BLOG-CN

一、简介

为什么我要用react?JQuery也挺好的呀?

1、因为浏览器和JavaScript一直在更新,新版前端框架可以更好对接新的API,更好的利用浏览器的能力, 提供更新潮强大的功能。

2、react有其庞大的生态系统,如插件、工具、库等,对开发者更省力

二、React主要发展历程

2011 Facebook内部使用

2013 Facebook开源

2015 Facebook发布React Native(干掉了iOS和Android开发岗位)

2017 React发布Fiber架构

2019 React16.8引入Hooks

2022 React 18 发布Concurrent Mode和Server Component

2024 React 19RC发布

三、React特性

1、组件化: 代码复用度高
2、虚拟DOM: 减少不必要的DOM操作和渲染
3、JSX: 易于理解和使用
4、跨平台: ReactNative
5、Concurrent Mode: 可中断的异步更新

四、React原理

React15架构:

1、Reconciler(协调器)------ 负责找出变化的组件

2、Renderer(渲染器)------ 负责将变化的组件渲染到页面上

此架构弊端: Reconciler是递归渲染,过程不可中断,当更新任务过大用时过久就会造成页面卡顿

React16架构:

1、Scheduler(调度器)------ 调度任务的优先级,高优任务优先进入

2、ReconcilerReconciler(协调器)------ 负责找出变化的组件

3、Renderer(渲染器)------ 负责将变化的组件渲染到页面上

此架构基于Fiber,时间切片,优先级调度,实现了渲染过程的可中断更新,在浏览器资源上限内最高效率流畅更新页面。

实现步骤:

1.虚拟DOM一个用来描述 UI 结构的 JavaScript 对象,用于抽象表示浏览器中真实的DOM节点,体积轻量,不绑定实际DOM具有的属性和方法。

java 复制代码
// 虚拟 DOM 对象
const virtualDOM = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

虚拟DOM的作用

每一个浏览器引擎都包含渲染引擎和JS引擎,二者各司其职。JS引擎执行JS快速不费力,可对用户不可见。

渲染引擎渲染页面比较耗费浏览器资源,直接和用户交互。

在接收到DOM更新任务时,虚拟DOM可作为真实DOM替身,缓冲计算好,最后统一更新到真实DOM树上,减少不必要的对DOM的操作和渲染。

当虚拟DOM有唯一标识时,还可以实现对应真实DOM节点的复用。

React Fiber 架构

Fiber Node: 一个典型的 Fiber 节点包含以下几个关键属性:
1、type: 组件的类型(例如函数组件、类组件、DOM 元素等)。
key: 用于标识节点的唯一键。
stateNode: 与 Fiber 节点对应的实际 DOM 节点或组件实例。
child: 指向第一个子节点的指针。sibling:指向下一个兄弟节点的指针。
return: 指向父节点的指针。
pendingProps: 新的属性,在 Fiber 树更新时使用。
memoizedProps: 上一次渲染时的属性。
memoizedState: 上一次渲染时的状态。
alternate: 指向当前 Fiber 节点的另一个版本(用于双缓存机制)。

Fiber Tree: 通过每个Fiber的child,sibling,return节点链接形成的链表结构。这种结构使得 React 可以在不影响其他节点的情况下,灵活地插入、删除或更新Fiber节点。React 遍历 Fiber 树时,通常使用深度优先搜索(DFS)。

双缓存机制: 在React中最多会同时存在两棵Fiber树。当前屏幕上显示内容对应的Fiber树称为current Fiber树,正在内存中构建的Fiber树称为workInProgress Fiber树。

current Fiber树中的Fiber节点被称为current fiber,workInProgress Fiber树中的Fiber节点被称为workInProgress fiber,他们通过alternate属性连接。

React应用的根节点通过使current指针在不同Fiber树的rootFiber间切换来完成current Fiber树指向的切换。

即当workInProgress Fiber树构建完成交给Renderer渲染在页面上后,应用根节点的current指针指向workInProgress Fiber树,此时workInProgress Fiber树就变为current Fiber树。

这种在内存中构建并直接替换的技术叫做双缓存

时间切片

前面提到的每一个浏览器引擎都包含渲染引擎和JS引擎,这两个引擎的工作是互斥的,同一时刻只能工作一个。

浏览器的刷新频率受限于显示器的刷新频率。以60Hz为例,浏览器每1000ms刷新16次,说明浏览器的一个刷新周期是16.6ms。

在浏览器每个刷新周期内,会按次序执行以下工作,JS脚本执行 ----- 样式布局 ----- 样式绘制

其中的JS脚本执行时间如果过长,就会导致刷新周期内无法执行样式绘制,形成掉帧,造成用户视觉上的页面卡顿。

为了解决这种问题,于是诞生了时间切片。

React,在浏览器每一帧刷新周期内,预留一些时间给 JS 线程,利用这部分时间更新组件(可以看到,在源码中,预留的初始时间是 5ms)。

当预留的时间不足以执行完全部的JS时,React将线程控制权交还给浏览器使其有时间渲染 UI,React则等待下一帧时间到来继续被中断的工作。

java 复制代码
function performUnitOfWork(fiber) {  
	// 处理当前 Fiber 节点  
	beginWork(fiber);  

	// 如果有子节点,处理子节点  
	if (fiber.child) {    
		return fiber.child;  
	} 
	 
	// 如果没有子节点,处理兄弟节点或返回父节点  
	let nextFiber = fiber;  
	while (nextFiber) {    
		completeWork(nextFiber);    
		if (nextFiber.sibling) {      
			return nextFiber.sibling;    
		}    
		nextFiber = nextFiber.return;  
	}
}

function workLoop(deadline) {  
	let shouldYield = false;  
	while (nextUnitOfWork && !shouldYield) {    
		nextUnitOfWork = performUnitOfWork(nextUnitOfWork);  
		shouldYield = deadline.timeRemaining() < 1;  
	}  

	if (!nextUnitOfWork) {    
		commitRoot();  
	} else {    
		requestIdleCallback(workLoop);  
	}
}

// 开始渲染
requestIdleCallback(workLoop);

优先级调度

优先级级别: React 定义了多个优先级级别,用于区分不同类型的任务。主要的优先级级别包括:
1、Immediate: 立即执行的任务,通常用于用户输入等需要立刻响应的操作。如文本框输入、按钮点击等。
2、User-blocking: 用户阻塞任务,稍低于立即执行的任务,但仍然需要快速响应,影响用户界面交互流畅性。如拖拽、滑动等。
3、Normal: 正常优先级任务,常规更新,如组件的状态更新、网络请求完成后的数据处理等。Low:低优先级任务,如后台数据同步,定时器。
4、Idle: 空闲优先级任务,只有在浏览器空闲时才会执行。

优先级实现: lane模型借鉴了同样的概念,使用31位的二进制表示31条赛道,位数越小的赛道优先级越高,某些相邻的赛道拥有相同优先级。

调度流程:

1、当需要执行一个任务时,React 会创建一个任务对象,并将其添加到优先级队列中。任务对象包含任务的优先级、执行回调和其他相关信息。

2、调度器会根据任务的优先级对队列中的任务进行排序。高优先级任务会排在队列的前面,低优先级任务则排在后面。

3、调度器会从队列中取出最高优先级的任务并执行它。如果当前有更高优先级的任务到来,调度器会中断当前任务,优先执行高优先级任务。

4、调度器会根据浏览器的空闲时间和任务的优先级来调度任务的执行,确保高优先级任务能够及时响应。(React 使用 requestIdleCallback 和 requestAnimationFrame 等浏览器 API 来实现这一点。

五、流程汇总

相关推荐
詩句☾⋆᭄南笙4 分钟前
初识Vue
前端·javascript·vue.js
minji...7 分钟前
C++ 详细讲解vector类
开发语言·c++
黑客飓风9 分钟前
从基础功能到自主决策, Agent 开发进阶路怎么走?
面试·log4j·bug
LiuYaoheng10 分钟前
【Android】View 的基础知识
android·java·笔记·学习
勇往直前plus18 分钟前
Sentinel微服务保护
java·spring boot·微服务·sentinel
星辰大海的精灵18 分钟前
SpringBoot与Quartz整合,实现订单自动取消功能
java·后端·算法
小鸡脚来咯21 分钟前
一个Java的main方法在JVM中的执行流程
java·开发语言·jvm
江团1io022 分钟前
深入解析三色标记算法
java·开发语言·jvm
Javian29 分钟前
浅谈前端工程化理解
前端
天天摸鱼的java工程师30 分钟前
RestTemplate 如何优化连接池?—— 八年 Java 开发的踩坑与优化指南
java·后端