react16-reactDom.render流程分析
背景
距离react16发布已经过去很久了,facebook开发团队耗时2年多,究竟做了什么呢。从下面两张图中可以很直观的看出,react16带来的性能优化
造成这样的现象主要是因为:单个网页由js、UI渲染线程、浏览器事件触发线程、http请求线程、EventLoop轮询的处理线程等线程组成,其中js引擎线程和ui渲染线程是互斥的,也就是说在处理js任务时,页面将停止渲染,一旦js占用时间过长,造成页面每秒渲染的帧数过低,就会给用造成很明显的卡顿感。
优化内容
新增了Portals、Fragments的组件类型,新增了componentDidCatch、static getDerivedStateFromProps、getSnapshotBeforeUpdate声明周期,componentWillMount、componentWillReceiveProps、componentWillUpdate将会在未来被移除,支持自定义的dom属性,扩展了render函数可返回的类型
引入异步架构,优化了包括动画,布局和手势的性能。
- 把可中断的工作拆分成小任务
- 对正在做的工作调整优先次序、重做、复用上次(做了一半的)成果
- 项目体积大幅度缩小,相比前一个大版本,react + react-dom的体积从161.kb(49.8kb gzipped)缩减到了109kb(34.8 kb gzipped),优化幅度高达30%。
jsx
编译前:
<h1 color="red">Hello, world!</h1>
复制代码
编译后:
React.createElement("h1", {color: "red"}, "Hello, world!")
复制代码
ReactDom.render
将react元素渲染到真实dom中。
ReactDOM.render(element,container,[callback]
)
复制代码
在线尝试
legacyRenderSubtreeIntoContainer
这个方法除主要做了两件事:
- 清除dom容器元素的子元素
while ((rootSibling = container.lastChild)) {container.removeChild(rootSibling);
}
复制代码
- 创建ReactRoot对象
Fiber
react在进行组件渲染时,从setState开始到渲染完成整个过程是同步的(“一气呵成”)。
如果需要渲染的组件比较庞大,js执行会占据主线程时间较长,会导致页面响应度变差,使得react在动画、手势等应用中效果比较差。 为了解决这个问题,react团队经过两年的工作,重写了react中核心算法——reconciliation。
规划阶段-scheduleWork
规划更新的过期时间和优先级
ExpirationTime
在react16中,随处可见expirationTime这个值,这个值的含义是:
- 所谓的到期时间(ExpirationTime),是相对于调度器初始调用的起始时间而言的一个时间段;调度器初始调用后的某一段时间内,需要调度完成这项更新,这个时间段长度值就是到期时间值。
- 目前react16的异步更新和优先级更新尚未完善,因此本文对此功能将暂不做深究。
priority
组件更新的优先级,react16暂未启用,不做深究。
调和-reconciliation
React算法,用于计算新旧树上需要更新的部分
workLoop
生成FiberTree
beginWork
根据fiber.tag类型,更新不同的fiber节点。
节点类型如下:
switch (workInProgress.tag) {case IndeterminateComponent:return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);case FunctionalComponent:return updateFunctionalComponent(current, workInProgress);case ClassComponent:return updateClassComponent(current, workInProgress, renderExpirationTime);case HostRoot:return updateHostRoot(current, workInProgress, renderExpirationTime);case HostComponent:return updateHostComponent(current, workInProgress, renderExpirationTime);case HostText:return updateHostText(current, workInProgress);case TimeoutComponent:return updateTimeoutComponent(current, workInProgress, renderExpirationTime);case HostPortal:return updatePortalComponent(current, workInProgress, renderExpirationTime);case ForwardRef:return updateForwardRef(current, workInProgress);case Fragment:return updateFragment(current, workInProgress);case Mode:return updateMode(current, workInProgress);case Profiler:return updateProfiler(current, workInProgress);case ContextProvider:return updateContextProvider(current, workInProgress, renderExpirationTime);case ContextConsumer:return updateContextConsumer(current, workInProgress, renderExpirationTime);default:invariant_1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
复制代码
completeWork
创建dom节点,初始化dom属性
更新阶段
根据前面计算出来的更新类型,在真实dom树上执行对应的操作
commitRoot
执行更新操作,分三次递归
- commitBeforeMutationLifecycles:调用getSnapshotBeforeUpdate声明周期
- commitAllHostEffects:执行所有会产生副作用的操作,插入、更新、移除、ref的unmount
- commitAllLifeCycles:生命周期
小技巧
- 阅读源码时,可以在本地用create-react-app新建一下小demo项目,然后直接在node_modules中的react-dom.development.js和react.development.js两个文件里的对应方法打断点。
参考
- React16.2源码解析
- React 16 Fiber源码速览
- react官方文档
- React Fiber
- React Fiber初探
- React Fiber Architecture
后续
- 事件系统分析
- setState分析
react16-reactDom.render流程分析相关推荐
- ReactDOM.render 是如何串联渲染链路的?(中)
ReactDOM.render 是如何串联渲染链路的?(中) render 阶段可以认为是整个渲染链路中最为核心的一环,因为反复强调"找不同"的过程,恰恰就是在这个阶段发生的. ...
- 03 渲染元素ReactDOM.render
React与ReactDOM是2个不同的库,根节点内的所有内容(和DOM更新.渲染相关)由ReactDOM来管理 一个React应用只有一个根节点 用ReactDOM.render将React元素渲染 ...
- Laravel Kernel引导流程分析
Laravel Kernel引导流程分析 代码展示 protected function sendRequestThroughRouter($request) {# $this->app-> ...
- ReactDOM.render(...) 渲染方法
React代码的书写格式和以前的JS有很大的不同,下面通过对这段代码进行分析了解一下他. 以前使用Javascript定义一个变量用var,ES6加入了const关键字,用来定义一个常量: const ...
- 03.ReactDOM.render
ReactDOM.render 上文说的是把jsx转换成VDom 而ReactDom.render则是把VDom渲染成真实的Dom节点(本篇幅只涉及到渲染,没有涉及到更新.调度等等) 我们在写reac ...
- 浅显易懂的Django架构流程分析
Django的运行方式 运行Django项目的方法很多,一种是在开发和调试中经常用到的runserver方法,使用Django自己的Web Server.另外一种就是使用fastcgi, uWSGI等 ...
- DRF基本使用及执行流程分析 | APIView源码分析
DRF基本使用及执行流程分析 介绍: # 使用的都是CBV的方式 ,继承的类为drf提供的类(提供的类很多) # 这里目前继承使用APIView类 # 因为APIView是所有类的基类,其他类可能拓展 ...
- Android 7.0 Launcher3的启动和加载流程分析----转载
Android 7.0 Launcher3的启动和加载流程分析,Launcher的本质就是一个普通应用,它比普通应用多配置了Category的Android:name="android ...
- VLC架构及流程分析
0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...
最新文章
- UITextField 详解
- u盘安装浪潮服务器_浪潮服务器NF84260M3安装Windows server 2012 R2
- UVA 10273 Eat or not to Eat?
- 关于PrintQueueCollection()类,跨线程调用错误“线程无法访问此对象,因为另一个线程拥有该对象”
- redis的Python接口调用
- linux usb 升级脚本,linux – 使用bash脚本更新CRON
- L1-1 PTA使我精神焕发 (5 分)
- GNU开发工具——Bochs模拟器
- C++入门——Day2_处理数据
- 产品生命周期管理PLM技术研究
- chromecast 协议_因此,您刚刚获得了Chromecast。 怎么办?
- 计算机里的word怎么重装,word能卸载重装吗 word卸载重装
- 14、弱电工程综合布线系统常用的线材及设备图文资料
- 伙伴云品牌升级:logo换新,调性更潮
- 互联网晚报 | 9月16日 星期四 | 网易云音乐发布“村民证”;阿里社区电商品牌升级为“淘菜菜”;高德打车上线“实景上车点”
- 用Java基础来编写一个彩票中奖代码
- 拼多多按关键词搜索示例
- 怎样才能快速地将爱奇艺qsv格式转换成mp4视频
- java使用POI操作excel
- 瑞吉外卖-移动端菜品展示功能,购物车添加菜品及修改等功能,用户下单功能及历史订单派送功能
热门文章
- 网商微信实名认证FAQ
- 若依前端table中如何显示图片?
- MyBlog前端开发2
- Spring 5.X+CXF 3.X 开发SOAP Web Service Client客户端实例
- Ext JS 4 升级指南
- 怎么使用计算机的移动与复制,Excel移动和公式的复制
- oracle ocm 考题,2012年10 月oracle 10g ocm 认证 考试 真题 题库
- oracle 关于归档的视图,10G中,什么视图可以看归档空间的大小
- mysql事件不定时执行_Mysql 中的事件//定时任务
- 【编程帮助】python中字符串前的 r、b、u、f 的含义及用法