Time Slicing (时间分片)
React 在渲染(render)的时候,不会阻塞现在的线程 如果你的设备足够快,你会感觉渲染是同步的。如果你设备非常慢,你会感觉还算是灵敏的、 虽然是异步渲染,但是你将会看到完整的渲染,而不是一个组件一行行的渲染出来 同样书写组件的方式
Dan为我们做了一个有趣的Demo:
- 同步模式下,我们没输入一个字符,React就开始渲染,当React渲染一颗巨大的树的时候,是非常卡的,所以才会有shouldUpdate的出现;
- Debounced模式简单的来说,就是延迟渲染,比如,当你输入完成以后,再开始渲染所有的变化。这么做的坏处就是,至少不会阻塞用户的输入了,但是依然有非常严重的卡顿
- 异步渲染模式就是不阻塞当前线程,继续跑。在视频里可以看到所有的输入,表上都会是原谅色的。
简单的来说,react的异步渲染其实就是拉长了render的时间,一次跑一点,所以机器性能很差的,会看到react渲染时有稍微的延迟,但是不是卡顿。
Suspense(/səˈspens/ )悬停(也可以叫做暂停)
- 在render函数中,我们可以写入一个异步请求,请求数据
- react会从我们缓存中读取这个缓存
- 如果有缓存了,直接进行正常的render
- 如果没有缓存,那么会抛出一个异常,这个异常是一个promise
- 当这个promise完成后(请求数据完成),react会继续回到原来的render中(实际上是重新执行一遍render),把数据render出来
- 完全同步写法,没有任何异步callback之类的东西
调用render函数->发现有异步请求->悬停,等待异步请求结果->再渲染展示数据
主要解决:
Suspense主要解决的就是网络IO问题。网络IO问题其实就是我们现在用Redux+saga等等一系列乱七八糟的库来解决的「副作用」问题。react出生到现在都存在的「异步副作用」的问题,而且解决得非常的优雅,使用的是「异步但是同步的写法」,我个人认为,这是最好的解决异步问题的方式。
Suspense的核心功能:同步的方式去书写代码
这个组件就与我们之前书写组件的方式有很大的差异,在react 的 render()函数中,异步去fetch数据是没用的,因为异步函数会在下一个JS事件循环中才会进行,此时,已经渲染完毕了。所以拿到数据了也没用。
- 引入新的api,可以使得任何state更新暂停,直到条件满足时,再渲染(像async/await)
- 可以在任何一个组件里放置异步获取数据,而不用做多余的设置
- 在网速非常快的时候,可设置,整个数据到达Dom,更新完毕以后再渲染。在网速非常慢的时候,可设置,精确到单个组件的等待、以及更新,然后再渲染
使用
const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded
// Show a spinner while the profile is loading
<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>
react 16给我们带来的一些列重要变化:
- render/纯组件能够return任何数据结构,以及CreatePortal Api
- 新的context api,尝试代替一部分redux的职责
- babel的<>操作符,方便用户返回数组
- 异步渲染/时间切片(time slicing),成倍提高性能
- componentDidCatch,错误边界,框架层面上提高用户debug的能力
- 未来的Suspense,优雅处理异步副作用