Suspense技术起初是为了加载异步组件,但逐渐应用到了全部异步过程当中。其中,异步请求是Suspense最主要的使用场景。在不远的未来(React17/Vue3.1),基于Suspense的开发模式将成为主流,同时用户体验也会随着Suspense的使用获得优化。html
codesandbox.io/s/bold-cdn-…
node
codesandbox.io/s/kind-swar…
react
Suspense做为一个通用的技术,React和Vue在实现的思路上基本一致,核心原理有两方面:通讯和渲染。promise
通讯是指:Suspense与嵌入其内部的组件之间的通讯,即Suspense如何获取组件的异步状态性能优化
渲染是指:Suspense如何控制嵌入其内部的组件的渲染bash
结论:经过“隐式”的获取组件异步状态所关联的promise。网络
表面上看来,不论是Vue仍是React,咱们都没有给Suspense传任何promise相关的props,那么Suspense究竟是如何拿到的呢?咱们固化的思惟容易认为:props是通往组件的惟一入口。架构
实际上,Suspense做为一个框架内置的组件,它有“充分的自由”去获取任何运行时中存在的变量。并发
对于Vue来讲,若是在setup中"return"了一个promise,那么Vue就能拿到这个promise,并自动传递给离这个组件最近的那个Suspense。框架
对于React来讲,若是在render中"throw"了一个promise,那么React就能捕获到这个promise,并自动传递给离这个组件最近的那个Suspense。
这样,Suspense就能获取到组件的异步状态了。
结论:预渲染嵌入的组件到一个隐藏的dom容器中,并在异步状态resolve以后把预渲染的组件移动到真实的dom容器中。
Suspense总会预渲染组件到一个隐藏的容器,以后它会根据所关联的promise的状态进行抉择:
若是promise处于pending状态,那么就会渲染fallback组件到真实的dom容器中
若是promise到达resolve状态,那么就会直接把预渲染好的组件移动到真实的dom容器中,并清除fallback组件
若是promise到达reject状态,那么框架会直接抛出reject的错误,后面能够被ErrorBoundary接收
在组件中加载异步数据是业务场景中最多见的需求,组件的状态会根据异步数据的状态不一样而变化,一般是:loading状态 -> 真实内容。
使用传统的v-if/v-else,或者jsx中的三元表达式的形式,去渲染不一样状态下对应的组件内容,实际会有性能问题:
// template
<Loading v-if="loading">loading...</Loading>
<Content v-else>真实内容</Content>
// jsx
(
loading ? <Loading>loading</Loading> : <Content>真实内容</Content>
)复制代码
在切换渲染两种不一样的element时,都伴随着组件的销毁与重建。而若是使用Suspense,真实内容和fallback这二者会同时存在,真实内容不会随着fallback出现而销毁,也不会随着fallback的消失而重建,相反真实内容只是在更新。
这样,用户体验就获得了第一阶段的优化,由于页面的渲染性能明显提高。
渲染性能已经获得明显的提高,那么咱们还能优化什么呢?React并发模式带来了新的思路:干掉loading状态。
React并发模式是React Fiber架构的应用,在React Fiber架构下,组件树的更新以组件为粒度被异步化,组件的更新能够被中断,从而不会阻塞主线程。
更多内容请看:reactjs.org/docs/concur…
实际环境中,用户的设备性能、网络速度各有不一样,有的人性能好网速快,有的人性能差网速慢,结果就致使这种状况:
设备条件 |
使用体验 |
缘由 |
---|---|---|
高 |
低 |
设备条件已经这么好了,加载数据毫秒级别,可是仍是要闪一下loading状态 |
低 |
高 |
设备条件很差,加载数据秒级别,有一个loading状态会很舒服 |
在React并发模式中结合使用Suspense,便可解决上述问题,这里有一个demo:
点击Refresh会更新列表
更新列表的接口耗时随机在0-1s之间
若是接口返回的时间在0.5s以内,则不会显示loading状态
若是接口返回的时间在0.5s以外,则会显示loading状态
是的,咱们彻底能够自行实现这个功能,无非是加一个定时器,只有超过某个时间后,才会显示loading。可是,这样咱们就享受不到Suspense预渲染带来的性能提高了。
虽然Vue在Suspense上没法贡献更多性能优化,可是Vue会从另一个方向:预分析vnode,根据类型不一样给予相应的patchFlag,并根据flag的不一样采起最高效的更新方式,带来显著的渲染性能提高。