关键词:react 快速响应实现、react 可中断更新、react IO瓶颈、react CPU瓶颈
react 是如何实现快速响应的?
我们日常使用App,浏览网页时,有两类场景会制约快速响应:
当遇到大计算量的操作或者设备性能不足使页面掉帧,导致卡顿。
发送网络请求后,由于需要等待数据返回才能进一步操作导致不能快速响应。
这两类场景可以概括为:
- CPU的瓶颈
- IO的瓶颈
CPU的瓶颈
主流浏览器刷新频率为60Hz,即每(1000ms / 60Hz)16.6ms浏览器刷新一次。
我们知道,JS可以操作DOM,GUI渲染线程与JS线程是互斥的。所以JS脚本执行和浏览器布局、绘制不能同时执行。
在每16.6ms时间内,需要完成如下工作: JS脚本执行 ----- 样式布局 ----- 样式绘制
当JS执行时间过长,超出了16.6ms,这次刷新就没有时间执行样式布局和样式绘制了。
比如我们可以通过一个循环, 渲染列表 3000 个组件, 那么这种渲染时间, 就肯定是远超过 16.6 ms 的, 页面就会感觉到卡顿。
如何解决这个问题呢?
答案是:在浏览器每一帧的时间中,预留一些时间给JS线程,React利用这部分时间更新组件(可以看到,在源码中,预留的初始时间是5ms)。
源码位置: https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/scheduler/src/forks/SchedulerHostConfig.default.js#L119
当预留的时间不够用时,React将线程控制权交还给浏览器使其有时间渲染UI,React则等待下一帧时间到来继续被中断的工作。
这种将长任务分拆到每一帧中,像蚂蚁搬家一样一次执行一小段任务的操作,被称为时间切片(time slice)
所以,解决CPU瓶颈的关键是实现时间切片,而时间切片的关键是:将同步的更新变为可中断的异步更新。
IO的瓶颈
网络延迟是前端开发者无法解决的。如何在网络延迟客观存在的情况下,减少用户对网络延迟的感知?
简单点儿来说, 就是在点击页面跳转的是时候提前去加载下一个页面的内容。 或者在当前页面 hold .5s 左右时间, 利用这个时间去加载下一个页面的内容。
从而达到下一个页面的快速交互
React实现了 Suspense
功能及配套的 hook——useDeferredValue
。
而在源码内部,为了支持这些特性,同样需要将同步的更新变为可中断的异步更新。