关于Vue中keep-alive的作用,以及在部分场景下由于避免重复请求、重复渲染的性能提升,想必大家都很清楚了,在此不再赘述。
但是在nuxt项目中使用keep-alive就有个问题,比如我有一个用到嵌套路由的页面,导航栏(或者标签页)由几个页面共享,然后根据路由切换页面内容。这应该是个很常见的场景,Vue的文档里keep-alive的部分用的也是这个例子。为了直观,放个图好了:
在这个场景下使用nuxt,虽然整个页面没有重复渲染(因为被keep-alive缓存了),但是每次都会触发asyncData
这个钩子,去服务端拿数据,这就是一个无谓的开销,而且还会阻塞渲染。这个问题在nuxt的pull request #5947里提到了,虽然最后被作者自己close掉了。
网上绝大部分的内容都没有提到这一点,只说写个<nuxt-child keep-alive />
就行了,还是稍微有点粗暴了。
在此之前,我考虑过这样几种处理方式:
- 在
asyncData
里使用缓存。但是,后来发现这种方案不太可行,因为asyncData
在服务端触发,无法调用this
,这意味着数据是无法缓存在组件里的,比如拿到数据之后放在data
里,然后每次都从data
里读数据。 - 使用
mounted
和activated
钩子,按照SPA的方式去写。这么写是没问题,但是如果我这么写的话,为什么要用nuxt来做SSR呢?因为我的场景需要SEO,同时希望减少闪屏,所以并不能采用这种方式。
后来看到这位dalao写了一种方案:https://juejin.im/post/5cff5f02e51d4510624f97ab,对我有很大的启发,主要的思路是只让asyncData
在服务端触发,然后在浏览器端做一些数据的获取。
但是反向思考一下,如果asyncData
不能避免,那我能不能把每次调用的开销降到最小呢?我们想一下,在一般的业务场景下,开销最大的是什么?显然是ajax(不包括在asyncData
里进行密集计算的场景)。那我只要避免ajax,就可以降低调用开销。所以思路就很明显了,缓存。
但是刚才也提到了,在asyncData
里使用缓存是不可行的,因为不能访问this
。再思考一下,既然不能用this
,那我用vuex的store不就行了?于是有了第一个方案。示意代码如下:
export