Fiber是什么,执行原理如何理解
Admin 2022-12-07 群英技术资讯 404 次浏览
在 react16
引入 Fiber
架构之前,react 会采用递归方法对比两颗虚拟DOM树,找出需要改动的节点,然后同步更新它们,这个过程 react
称为reconcilation(协调)。在reconcilation
期间,react
会同步执行操作,提交到真实 DOM 的更改,会一直占着浏览器的资源,不能中断,中断后就不能恢复,使得我们一些用户操作定时器等等事件无法得到响应,是一个非常糟糕的用户体验。
所以我们要解决的问题就是:解决React主线程长时间占用的一个问题。 这个时候,就引入了Fiber
架构。
Fiber
可以理解为是一个执行单元,也可以理解为是一种数据结构。每一个React元素都对应一个fiber对象,我们先看看fiber
中的属性:
function FiberNode( tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode, ) { // 作为静态数据结构的属性 this.tag = tag; // Fiber对应组件的类型 Function/Class/Host... this.key = key; // key属性 this.elementType = null; // 大部分情况同type,某些情况不同,比如FunctionComponent使用React.memo包裹 this.type = null; // 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName this.stateNode = null; // Fiber对应的真实DOM节点 // 用于连接其他Fiber节点形成Fiber树 this.parent = null; // 指向父级Fiber节点 this.child = null; // 指向子Fiber节点 this.sibling = null; // 指向右边第一个兄弟Fiber节点 this.index = 0; this.ref = null; // 作为动态的工作单元的属性 —— 保存本次更新造成的状态改变相关信息 this.pendingProps = pendingProps; this.memoizedProps = null; this.updateQueue = null; // class 组件 Fiber 节点上的多个 Update 会组成链表并被包含在 fiber.updateQueue 中。 函数组件则是存储 useEffect 的 effect 的环状链表。 this.memoizedState = null; // hook 组成单向链表挂载的位置 this.dependencies = null; this.mode = mode; // Effects this.flags = NoFlags; this.subtreeFlags = NoFlags; this.deletions = null; // 调度优先级相关 this.lanes = NoLanes; this.childLanes = NoLanes; // 指向该fiber在另一次更新时对应的fiber this.alternate = null; }
React Fiber 就是采用链表实现的,主要就是通过以下这几个属性表示:
this.parent = null; // 指向父级Fiber节点 this.child = null; // 指向子Fiber节点 this.sibling = null; // 指向右边第一个兄弟Fiber节点
假如我们要渲染下面这个元素树:
<div> <h1> <p> <a></a> </p> </h1> <h2></h2> </div>
我们看一下它的Fiber结构树:
每个fiber
元素都有这三个属性,观察上面图发现:
parent
:指向父级Fiber
节点:child
:指向子Fiber
节点sibling
:指向右边的兄弟节点我们可以把每个fiber
当做一个执行单元,每次执行完一个执行单元。React
会去检测还剩多少时间,如果没有时间就将控制权让给浏览器,如果还有时间就去执行下一个执行单元。
这里就涉及到了一个问题,react
如何和浏览器进行控制权的交接,浏览器何时空闲呢?。我们先来了解一下浏览器的工作:
在浏览器中,我们所看到的页面是一帧一帧画出来的,渲染的帧率与设备的刷新率保持一致。通常情况下,我们的设备都是60Hz
,也就是说,1s
屏幕会刷新60
次。当每秒内绘制的帧数(FPS
)超过60
时,页面渲染是流畅的,当帧数小于60
时,会明显感受到卡顿。下面来看完整的一帧中,浏览器具体做了哪些事情:
Begin Frame
(开始帧),即每一帧的事件,包括 window.resize
、scroll
、media query change
等requestAnimationFrame(rAF
),即在每次绘制之前,会执行 rAF
回调Layout
操作,包括计算布局和更新布局,即这个元素的样式是怎样的,它应该在页面如何展示Paint
操作,得到树中每个节点的尺寸与位置等信息,浏览器针对每个元素进行内容填充Idle Peroid
),可以在这时执行 requestIdleCallback
里注册的任务这样我们把工作单元的任务放到requestIdleCallback
回调当中,如果浏览器处理完上述的任务(布局和绘制之后),还有盈余时间,这个时候就可以执行我们的工作单元了。每次执行完一个执行单元。React
会去检测还剩多少时间,如果没有时间就将控制权让给浏览器。直至,React
和浏览器通过合作式调度完美配合,实现高性能应用。
从根节点开始调度和渲染可以分为两个阶段:render
和commit
。 先来了解下这几个关键名词:
workInProgress
代表当前正在执行更新的 Fiber
树。在 setState
或者渲染 后,会构建一颗 Fiber
树,也就是 workInProgress tree
,
首次渲染之后,React
会生成一个对应于 UI
渲染的 fiber
树,称之为 current 树。在新一轮更新时 workInProgress tree
再重新构建,新workInProgress
的节点通过 alternate
属性和 currentFiber
的节点建立联系。
effect list
可以理解为是一个存储 effect
副作用列表容器。
在render
阶段中,会找到所有节点的变更,比如说节点新增,编辑,删除等等。这些变更React
称之为副作用effect。在这个阶段中,也可以认为是diff
阶段,主要就是对比currentFiber tree
和workInProgress tree
之间的差异,然后打上标记
。
在这个阶段,任务是可以终止的。React 可以根据当前可用的时间片处理一个或多个 fiber
节点,并且得益于 fiber
对象中存储的元素上下文信息以及构成的链表结构,使其能够将执行到一半的工作仍保存在内存的链表中。在重新获得控制权后,又可以根据保存在内存中的上下文信息快速找到停止的fiber
节点,然后继续工作执行工作单元。
遍历Fiber tree
时采用的是后序遍历方法
在遍历的过程中,我们会去收集所有变更的节点产出的effect
,每个effect
通过链表的方式链接。每个 fiber 有两个属性
中间的使用nextEffect
做成一个单链表。
与render
阶段不同,commit
阶段是同步操作的。
因为在commit
阶段是更新真实的dom
,所以更新dom不可能一点一点去更新,这样用户体验会极差。所以commit
阶段必须是同步执行,一次更新到位。
首先的事情是遍历effect-list
列表,拿到每一个 effect
存储的信息,根据副作用类型 effectTag
执行相应的处理并提交更新到真正的 DOM
。所有的effects
都会在layout phase
阶段之前被处理。当该阶段执行结束时,workInProgress树
会被替换成current树
。到这里,根据收集到的变更信息完成了刷新操作。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
commentBox1.创建管理员首先开启Mongo服务,然后切换admin数据库,一开始是没有这个数据库的。>useadmin12.然后创建用户和密码:>db.createUser({user:’root’,pwd:’root1234’,rol
现在很多网站很软件都添加了短信验证的功能,我们在使用时发现一般获取一次验证码之后,需要等待一段时间才能获取下一次验证码,那么发送短信验证间隔是如何实现呢?这篇文章就主要介绍使用js实现短信验证码倒计时功能。
这篇文章主要介绍了前端JavaScript多数元素的算法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
目录一、webpack介绍1、由来2、介绍3、作用4、拓展说明5、webpack整体认知二、webpack安装1、安装node2、安装cnpm3、安装nrm的两种方法4、安装webpack三、webpack配置0、搭建项目结构1、初始化一个项目(会创建一个package.json文件)2、在当前的项目中安装Webpac
这篇文章主要介绍了如何在React中直接使用Redux,目前redux在react中使用是最多的,所以我们需要将之前编写的redux代码,融入到react当中去,本文给大家详细讲解,需要的朋友可以参考下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008