React理念
用 JavaScript 构建快速响应的大型 Web 应用程序。
速度快
使用
PureComponent
或React.memo
构建组件使用
shouldComponentUpdate
生命周期钩子渲染列表时使用
key
使用
useCallback
和useMemo
缓存函数和变量
响应自然
将人机交互研究的结果整合到真实的 UI 中。
同步的更新变为可中断的异步更新
在浏览器每一帧的时间中,预留一些时间给JS线程,React利用这部分时间更新组件(可以看到,在源码中,预留的初始时间是5ms)
当预留的时间不够用时,React将线程控制权交还给浏览器使其有时间渲染UI,React则等待下一帧时间到来继续被中断的工作。
React15架构
Reconciler(协调器)
每当有更新发生时,Reconciler会做如下工作:
调用函数组件、或class组件的
render
方法,将返回的JSX转化为虚拟DOM将虚拟DOM和上次更新时的虚拟DOM对比
通过对比找出本次更新中变化的虚拟DOM
通知Renderer将变化的虚拟DOM渲染到页面上
Renderer(渲染器)
ReactDOM渲染器,浏览器环境渲染
ReactNative渲染器,渲染App原生组件
ReactTest渲染器,渲染出纯Js对象用于测试
ReactArt渲染器,渲染到Canvas, SVG 或 VML (IE8)
递归更新的缺点
主流的浏览器刷新频率为60Hz,即每(1000ms / 60Hz)16.6ms浏览器刷新一次。我们知道,JS可以操作DOM,GUI渲染线程
与JS线程
是互斥的。所以JS脚本执行和浏览器布局、绘制不能同时执行。
在每16.6ms时间内,需要完成如下工作:
JS脚本执行 ----- 样式布局 ----- 样式绘制
当JS执行时间过长,超出了16.6ms,这次刷新就没有时间执行样式布局和样式绘制了。
对于用户在输入框输入内容这个行为来说,就体现为按下了键盘按键但是页面上不实时显示输入。
对于React
的更新来说,由于递归执行,所以更新一旦开始,中途就无法中断。当层级很深时,递归更新时间超过了16ms,用户交互就会卡顿。
React16架构
Scheduler(调度器)
既然我们以浏览器是否有剩余时间作为任务中断的标准,那么我们需要一种机制,当浏览器有剩余时间时通知我们。React
实现了功能更完备的requestIdleCallback
polyfill,这就是Scheduler。除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。
Reconciler(协调器)
在React16中,Reconciler与Renderer不再是交替工作。当Scheduler将任务交给Reconciler后,Reconciler会为变化的虚拟DOM打上代表增/删/更新的标记,类似这样:
export const Placement = /* */ 0b0000000000010;export const Update = /* */ 0b0000000000100;export const PlacementAndUpdate = /* */ 0b0000000000110;export const Deletion = /* */ 0b0000000001000;