背景

距离react16发布已经过去很久了,facebook开发团队耗时2年多,究竟做了什么呢。从下面两张图中可以很直观的看出,react16带来的性能优化

造成这样的现象主要是因为:单个网页由js、UI渲染线程、浏览器事件触发线程、http请求线程、EventLoop轮询的处理线程等线程组成,其中js引擎线程和ui渲染线程是互斥的,也就是说在处理js任务时,页面将停止渲染,一旦js占用时间过长,造成页面每秒渲染的帧数过低,就会给用造成很明显的卡顿感。

优化内容

  1. 新增了Portals、Fragments的组件类型,新增了componentDidCatch、static getDerivedStateFromProps、getSnapshotBeforeUpdate声明周期,componentWillMount、componentWillReceiveProps、componentWillUpdate将会在未来被移除,支持自定义的dom属性,扩展了render函数可返回的类型

  2. 引入异步架构,优化了包括动画,布局和手势的性能。

  • 把可中断的工作拆分成小任务
  • 对正在做的工作调整优先次序、重做、复用上次(做了一半的)成果
  1. 项目体积大幅度缩小,相比前一个大版本,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

这个方法除主要做了两件事:

  1. 清除dom容器元素的子元素
while ((rootSibling = container.lastChild)) {container.removeChild(rootSibling);
}
复制代码
  1. 创建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

执行更新操作,分三次递归

  1. commitBeforeMutationLifecycles:调用getSnapshotBeforeUpdate声明周期
  2. commitAllHostEffects:执行所有会产生副作用的操作,插入、更新、移除、ref的unmount
  3. 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流程分析相关推荐

  1. ReactDOM.render 是如何串联渲染链路的?(中)

    ReactDOM.render 是如何串联渲染链路的?(中)   render 阶段可以认为是整个渲染链路中最为核心的一环,因为反复强调"找不同"的过程,恰恰就是在这个阶段发生的. ...

  2. 03 渲染元素ReactDOM.render

    React与ReactDOM是2个不同的库,根节点内的所有内容(和DOM更新.渲染相关)由ReactDOM来管理 一个React应用只有一个根节点 用ReactDOM.render将React元素渲染 ...

  3. Laravel Kernel引导流程分析

    Laravel Kernel引导流程分析 代码展示 protected function sendRequestThroughRouter($request) {# $this->app-> ...

  4. ReactDOM.render(...) 渲染方法

    React代码的书写格式和以前的JS有很大的不同,下面通过对这段代码进行分析了解一下他. 以前使用Javascript定义一个变量用var,ES6加入了const关键字,用来定义一个常量: const ...

  5. 03.ReactDOM.render

    ReactDOM.render 上文说的是把jsx转换成VDom 而ReactDom.render则是把VDom渲染成真实的Dom节点(本篇幅只涉及到渲染,没有涉及到更新.调度等等) 我们在写reac ...

  6. 浅显易懂的Django架构流程分析

    Django的运行方式 运行Django项目的方法很多,一种是在开发和调试中经常用到的runserver方法,使用Django自己的Web Server.另外一种就是使用fastcgi, uWSGI等 ...

  7. DRF基本使用及执行流程分析 | APIView源码分析

    DRF基本使用及执行流程分析 介绍: # 使用的都是CBV的方式 ,继承的类为drf提供的类(提供的类很多) # 这里目前继承使用APIView类 # 因为APIView是所有类的基类,其他类可能拓展 ...

  8. Android 7.0 Launcher3的启动和加载流程分析----转载

     Android 7.0 Launcher3的启动和加载流程分析,Launcher的本质就是一个普通应用,它比普通应用多配置了Category的Android:name="android ...

  9. VLC架构及流程分析

    0x00 前置信息 VLC是一个非常庞大的工程,我从它的架构及流程入手进行分析,涉及到一些很细的概念先搁置一边,日后详细分析. 0x01 源码结构(Android Java相关的暂未分析) # bui ...

最新文章

  1. UITextField 详解
  2. u盘安装浪潮服务器_浪潮服务器NF84260M3安装Windows server 2012 R2
  3. UVA 10273 Eat or not to Eat?
  4. 关于PrintQueueCollection()类,跨线程调用错误“线程无法访问此对象,因为另一个线程拥有该对象”
  5. redis的Python接口调用
  6. linux usb 升级脚本,linux – 使用bash脚本更新CRON
  7. L1-1 PTA使我精神焕发 (5 分)
  8. GNU开发工具——Bochs模拟器
  9. C++入门——Day2_处理数据
  10. 产品生命周期管理PLM技术研究
  11. chromecast 协议_因此,您刚刚获得了Chromecast。 怎么办?
  12. 计算机里的word怎么重装,word能卸载重装吗 word卸载重装
  13. 14、弱电工程综合布线系统常用的线材及设备图文资料
  14. 伙伴云品牌升级:logo换新,调性更潮
  15. 互联网晚报 | 9月16日 星期四 | 网易云音乐发布“村民证”;阿里社区电商品牌升级为“淘菜菜”;高德打车上线“实景上车点”
  16. 用Java基础来编写一个彩票中奖代码
  17. 拼多多按关键词搜索示例
  18. 怎样才能快速地将爱奇艺qsv格式转换成mp4视频
  19. java使用POI操作excel
  20. 瑞吉外卖-移动端菜品展示功能,购物车添加菜品及修改等功能,用户下单功能及历史订单派送功能

热门文章

  1. 网商微信实名认证FAQ
  2. 若依前端table中如何显示图片?
  3. MyBlog前端开发2
  4. Spring 5.X+CXF 3.X 开发SOAP Web Service Client客户端实例
  5. Ext JS 4 升级指南
  6. 怎么使用计算机的移动与复制,Excel移动和公式的复制
  7. oracle ocm 考题,2012年10 月oracle 10g ocm 认证 考试 真题 题库
  8. oracle 关于归档的视图,10G中,什么视图可以看归档空间的大小
  9. mysql事件不定时执行_Mysql 中的事件//定时任务
  10. 【编程帮助】python中字符串前的 r、b、u、f 的含义及用法