React-fiber架构的解释

React-fiber架构解析

什么是fiber

React中虚拟dom是对真实dom的一种简化,但是一些真实dom能做的事情,虚拟dom做不了,于是就有了fiber,fiber其实是指一种数据结构,有很多的属性,它可以用一个纯的JS对象来表示,借由fiber上的属性做到一些虚拟dom功能上的拓展

//简化的fiber对象
const fiber={
    tag,//fiber类型
    key,
    type,//标签类型
    stateNode, //当前fiber实例
    child,     //子节点
    subling,   //兄弟节点
    return,    //父节点
    index,
    memoizedState,//当前fiber的state
    memoizedProps//当前fiber的props
    pendingProps,//传进来的新的props
    effectTag,
    //当前节点要进行何等更新  placement新插入 update更新 deletion删除 placementAndUpdate插入加更新 noWork当前节点没有任何工作
    firstEffect,//当前有更新的第一个子节点
    lastEffect,//当前节点有更新的最后一个子节点
    nextEffect,//下一个要跟更新的子节点
    alternate,//连接current和workInProgress树
    updateQueue,//一条链表挂载的是当前fiber的新的状态
    //....其他属性
}

一、fiber架构

以往版本不足:

界面DOM节点多,渲染比较耗时

React为了弥补之前版本的一些不足,设计了一些新的算法,由新算法设计出现了fiber这种数据结构

fiber数据结构+新的算法=fiber架构

JSX:React语法糖 描述UI界面

1.1、react应用从始至中管理这基本的三样东西

1、Root-- (应用根 一个对象 存在一个属性指向current树,一个属性指向workInProgress树 )

2、current树 (保存上一次状态的fiber树 ,且每个fiber节点都对应这一个jsx节点)

3、workInProgress树(保存每次新的状态的fiber树,并且每个fiber节点都对应一个jsx节点)

1.2、react初次渲染

1、react在第一次开始创建root时, 就会同时创建uninitialFiber对象 (未初始化的fiber)、

使react的current指向了uninitialFiber对象 假设为上一次状态

2、之后再去创建本次要用到的workInProgress树

二、Fiber 的主要工作流程:

  1. ReactDOM.render() 引导 React 启动或调用 setState() 的时候开始创建或更新 Fiber 树。
  2. 从根节点开始遍历 Fiber Node Tree, 并且构建 WokeInProgress Tree(reconciliation 阶段)。
    • 本阶段可以暂停、终止、和重启,会导致 react 相关生命周期重复执行。
    • React 会生成两棵树,一棵是代表当前状态的 current tree,一棵是待更新的 workInProgress tree。
    • 遍历 current tree,重用或更新 Fiber Node 到 workInProgress tree,workInProgress tree 完成后会替换 current tree。
    • 每更新一个节点,同时生成该节点对应的 Effect List。
    • 为每个节点创建更新任务。
  3. 将创建的更新任务加入任务队列,等待调度。
    • 调度由 scheduler 模块完成,其核心职责是执行回调。
    • scheduler 模块实现了跨平台兼容的 requestIdleCallback。
    • 每处理完一个 Fiber Node 的更新,可以中断、挂起,或恢复。
  4. 根据 Effect List 更新 DOM (commit 阶段)。
    • React 会遍历 Effect List 将所有变更一次性更新到 DOM 上。
    • 这一阶段的工作会导致用户可见的变化。因此该过程不可中断,必须一直执行直到更新完成。

三、React16版本之前的渲染方式

1、模拟render渲染

//作用:将元素渲染到界面
//参数:element 元素,rootPatent 渲染元素的根节点

let element =(
	
I M hero
哈哈哈
) function render(element,rootParent){ //1.创建元素 let dom=docment.createElement(element.type) //2.给元素添加属性 Object.keys(element.props).filter(prop=>prop!="children") .forEach(v=>dom[v]=element.props[v]) //3.将元素的子元素进行渲染(递归) if(Array.isArray(element.props.children)){ element.props.children.forEach(c=>render(c,dom)) }else{ dom.innerHTML=element.props.children; } }

2、element 元素Balbel编译后的数据结构 ,传入render()供react渲染

{
	"type": "div",
	"key": null,
	"ref": null,
	"props": {
		"id": "1",
		"children": ["I M hero", {
			"type": "div",
			"key": null,
			"ref": null,
			"props": {
				"children": "哈哈哈"
			},
			"_owner": null,
			"_store": {}
		}]
	},
	"_owner": null,
	"_store": {}
}

3、 引发问题

因为如果界面节点多,层次深,递归渲染比较耗时

且 js是单线程的,UI线程和JS线程互斥,会照成界面卡顿,

所以 react在新版本中引入了 fiber的架构模式

4、老的架构方式造成界面掉帧卡顿原因

JS执行js引擎和页面渲染在同一个线程中,GUI渲染和JS执行两者是互斥的,如果某个js任务执行时间过长,浏览器就会推迟渲染,造成页面掉帧(浏览器每个帧都会进行样式计算、布局和绘制操作),页面刷新率低于24fps,形成视觉上的界面卡顿

2、fiber是一个执行单元,每次执行完一个执行单元,Reacta就会检查现在还剩多少时间,如果没有时间就将控制权让出去

四、关于setState是否为异步的解析

1、正常情况下,没有使用组件情况下,是同步更新的

但是不会立即获取到最新的state的值,因为这种情况调用setState只是单纯的将传入的state值放入UpdateQueen这条链表上,未执行更新

但内部会执行一个回调函数,才会真正的更新state,再重新渲染(无法立即获取值)

2、当使用组件时才是真正的异步更新模式,无法立即获取最新的状态,并且在更新和渲染时,会将整个过长放入eventloop中去执行 ,这时候才是真正的异步(无法立即获取值)

3、当使用flushSync()API书写setState时,react更新渲染完全同步,react会立即更新及渲染过程(可以立即获取值)

4、addEventLister()回调中setState(),非合成事件 (可以立即获取值)

5、setState()第二个参数回调函数中读取最新state值

五、fiber如何被打断

在reconciliation 阶段,指创建fiber的过程 :React16将Dom节点打散成了相互独立且有联系的一个个fiber对象,他们之间存在优先级关系,

在渲染时, 通过将一个个fiber任务打散在浏览器渲染的每一帧中 ,而Fiber实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。

​ 实现方式是使用了浏览器的requestIdleCallback这一 API,可以让浏览器在空闲的时候执行回调,在回调参数中可以获取到当前帧剩余的时间,fiber 利用了这个参数,判断当前剩下的时间是否足够继续执行任务,如果足够则继续执行,否则暂停任务,并调用 requestIdleCallback 通知浏览器下次空闲的时候继续执行当前的任务。
React-fiber架构的解释_第1张图片

六、(React新版本中)fiber为什么要废弃一些生命周期

在 fiber 中,

更新分为两个阶段,

1、reconciliation(real爱可塞累神=>和解) 的阶段,这个阶段在计算前后 dom 树的差异,耗时长,可以被打断

2、然后是 commit 的阶段,这个阶段将把更新渲染到页面上,一口气把更新渲染到页面上,不会被打断

因此:

reconciliation 的阶段会被打断,可能会导致 commit 前的这些生命周期函数多次执行。react 官方目前已经把 componentWillMountcomponentWillReceivePropscomponetWillUpdate 标记为 unsafe,并使用新的生命周期函数 getDerivedStateFromPropsgetSnapshotBeforeUpdate 进行替换。

mit 前的这些生命周期函数多次执行。react 官方目前已经把 componentWillMountcomponentWillReceivePropscomponetWillUpdate 标记为 unsafe,并使用新的生命周期函数 getDerivedStateFromPropsgetSnapshotBeforeUpdate 进行替换。

你可能感兴趣的:(#,React,javascript,前端框架,reactjs)