React源码分析(2)
fiber是什么?如何创建的?
OK,话接上文,我们学习了creatRoot的workStream,接下来我们来聊聊,创建了节点之后,我们是如何将这个节点变成fiber的?
首先再来讲fiber的创建之前我们应该聊一聊什么是fiber
上文是React关于fiber的部分官方解释,这里简单贴出部分详解有需求观看的可以看下方链接
https://github.com/acdlite/react-fiber-architecture#what-is-reconciliation
简单来说fiber也是 Virtual DOM 的一种,
PS:如果有同学想要深入的先了解什么是 Virtual Dom 的话,这里作者推荐可以先去看一看 Snabbdom 这个库,Vue和React在某种意义上来说都是借鉴了这个库的一部分思想
下方是链接
https://github.com/snabbdom/snabbdom //很值得的一个学习虚拟dom的库,后期作者会出一期专门的文章
OK!那么,react是什么时期引入的fiber,又为什么引入?
React在16之前的版本并未使用fiber架构,在React16的版本中重构了Diff算法同时完成基于fiber实现的hooks方法
那么又是为什么引入呢?
从 React设计理念 和 React架构 中我们知道,在 v15
版本 Reconciler
采用递归的方式更新虚拟 DOM,这会导致什么问题呢?
由于递归过程是不能中断的,如果组件树的层级很深,递归更新时间超过了一帧,用户交互就会卡顿,所以为了解决这个问题,v16
将递归的无法中断的更新重构为异步的可中断更新。
通过上一期我们创建的项目然后debugger我们看到了fiber在真正运行时长得到底什么样子,OK,这里大家应该应该能看明白了。由于浏览器原因没有能够截成长图,可以对付看一下。
在这个地方我们可以看到也就是createRoot做了什么这篇文章中最后留下的疑问 createContainer 做了什么呢,其实就是在上文中,创建了这样的一个fiber对象返回。
好的!!!那么我们继续向下看源码吧,
通过这个 enableNewReconciler 这个参数来判断我们采用新的 R econciler 来渲染还是旧的版本,目前使用的是old版本
PS:(React 源码中, 后缀带old 的代表当前使用的, 带new 的是React 团队为了实验一些新的功能所使用的版本,我们只需要关注old里的功能)
OK,在学习之前我们来聊一下我们今天重点关注的内容都是哪些看下文
以上四个函数就是我们今天的学习目标
createContainer
creatFiberRoot
FiberRootNode
updateContainer
那么在深入学习这上面四个函数之前呢,我觉得我们可以先去看一下 Fiber 的的 type,先知道一下这玩意儿,他到底是什么** **
好的,具体参数作者都已经写上了注释,有兴趣的同学可以去自己在深入的查看一下每个参数他具体都做了什么,这里为了控制文章长度就不过多介绍了。
下面开始看方法吧
一、createContainer
其实这里就没什么好讲的了本质上就是闭包函数,处理初始化处理一些私有参数,从这里我们也可以看出,React在其本身的设计上其实利用了大量的闭包概念。这个时候其实也就不难看出,很多初级开发者同学在开发React作为了应用级开发的过程中偶尔出现内存泄漏的问题的原因在哪里了。
二、createFiberRoot
好的,看完上文这些代码,我们可以看到,其实本质上的创建逻辑就在这里了,在这个 createFiberRoot 这个执行栈中,我们本质上就做了三件事,创建 FiberNode、 状态绑定(effect的判断绑定)、初始化队列。
三、FiberRootNode
到这里呢其实fiberRootNode的逻辑就比较简单了,本质上就是个构造函数,来new一下初始化这个对象就好了,如果不理解的同学可以把它想象成一个类也行,下文的enable是基于初始化参数入参进行优化。这里没有展开详细讲,有兴趣的可以自己看一看这个参数具体的功用,是属于额外的优化配置,在同级目录下的ReactFeatureFlags文件中,可以看到具体配置。
四、updateContainer
前言:其实这段不应该放在这里来讲的,因为其实本质要结合调度器scheduler来聊的,但是这里先单独的讲讲他的 workStream 吧,
首先来聊他的入栈吧
在这里 render 的过程中进行更新,传入了两个参数一个是我们render的jsx节点一个是root根节点
上文两个参数一个根节点的时机和children的节点时机
OK!!触发的参数我们找到了,我们来看执行吧
看完上文的整个 updateContainer 的执行,可能会有同学一脸懵逼一头雾水,不知道到底干了什么,这个时候其实我们抛开那些各种的回调来看,在上文这段代码中,我们只要知道,update 本质上就是将我们需要更新的节点,参数放入到 scheduler 调度器中,然后由 scheduler 来决定更新的状态和时机就可以了,这个节点主要传入的一个参数是 lane 来决定执行的顺序机制了。
那么看完了到了这里,这篇文章的分享就算结束了,简单总结一下我们的定义吧
createContainer闭包调用了createFiberRoot,给了两个参数,判定是否服务端渲染和子树节点为null
createFiberRoot做了三件事,初始化fiberRootNode,绑定副作用,初始化队列
fiberRootNode构造函数,创建节点
updateContainer,找到节点,判断执行优先级,告诉scheduler
以上就是我们文章的核心内容了。当然,真实的React执行要比作者所讲的要复杂的很多,包括很多的优化计算以及错误边界的捕获处理,这里作者通通没有讲到,只是简单的聊整个的执行机制。如果有兴趣的同学还是可以自己去学习源码。作者的分析也只能代表作者自己的认知,也未必就是一定正确的。希望同学能有自己的认知。这里呢其实应该还应该讲一下 FiberNode 但是这里就省略了,和本章是有很多耦合的,可以自己去学习看一看
OK,文章结束,下一期我们开始聊一聊 scheduler 这个 React 的核心中的核心了!!!
参考文章:
React哲学 https://react.docschina.org/docs/thinking-in-react.html
React设计理念 https://github.com/campcc/blog/issues/44
React架构 https://github.com/campcc/blog/issues/45
有兴趣的同学可以关注一下作者哈~~