内容简介:距离react16发布已经过去很久了,facebook开发团队耗时2年多,究竟做了什么呢。从下面两张图中可以很直观的看出,react16带来的性能优化造成这样的现象主要是因为:单个网页由js、UI渲染线程、浏览器事件触发线程、http请求线程、EventLoop轮询的处理线程等线程组成,其中js引擎线程和ui渲染线程是互斥的,也就是说在处理js任务时,页面将停止渲染,一旦js占用时间过长,造成页面每秒渲染的帧数过低,就会给用造成很明显的卡顿感。编译前:
背景
距离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-reactDom.render流程分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【Tomcat学习笔记】启动流程分析--总体流程
- 【Tomcat学习笔记】启动流程分析--总体流程
- 以太坊源码分析(二):以太坊启动流程分析
- RxJava2源码分析(一):基本流程分析
- MapReduce运行流程分析
- Kubelet 启动流程分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
你凭什么做好互联网
曹政 / 中国友谊出版公司 / 2016-12 / 42.00元
为什么有人可以预见商机、超越景气,在不确定环境下表现更出色? 在规则之外,做好互联网,还有哪些关键秘诀? 当环境不给机会,你靠什么翻身? 本书为“互联网百晓生”曹政20多年互联网经验的总结,以严谨的逻辑思维分析个人与企业在互联网发展中的一些错误思想及做法,并给出正确解法。 从技术到商业如何实现,每个发展阶段需要匹配哪些能力、分解哪些目标、落实哪些策略都一一点出,并在......一起来看看 《你凭什么做好互联网》 这本书的介绍吧!