[React] react 是如何实现页面的快速响应?【热度: 696】

关键词: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

而在源码内部,为了支持这些特性,同样需要将同步的更新变为可中断的异步更新。