前言
这个服务端优化的想法是我在一篇文章看到的,可惜不记得文章的链接了,如果有印象的读者可以评论一下文章来源,谢谢。
背景
用Nuxt.js开发的网站,因为依赖于服务端的功能,无法使用nuxt generate去生成静态文件,用Nginx托管站点。
对于部分页面数据较多的页面,请求接口以及渲染页面的时间过长,影响用户体验,所以研究了缓存优化方案,去优化部分页面性能。
缓存使用到的算法
在这里我用的是LRU库,LRU缓存的核心在于能够把最不常使用的数据移除,让给最新读取的数据。如果有想要详细了解该算法的可以参考该文章: LRU算法
实现思路
- 在server端判断用户所访问的路径,若该路径是所需要缓存的页面,则在server端渲染完成后,将得到的html代码缓存到内存中。
- 在用户访问网站时,判断访问的页面是否有缓存,如果有缓存的话,则直接返回html代码,减少服务端渲染这一步骤的时间。
- 当被缓存的页面的数据需要更新时,应当把该页面的缓存给清空,等到获取到新的数据后,再重新缓存。
代码实现
- 创建缓存对象并导出该对象,使得后续的新增缓存和清空缓存操作的是同一个缓存对象。
// globalCache.js const LRU = require('lru-cache') const cachePage = new LRU({ // 最大缓存数量 max: 10, // 缓存过期时间(ms) maxAge: 1000 * 60 * 10 }) module.exports = cachePage
- 执行缓存操作
// pageCache.js const cachePage = require('./globalCache') export default function (req, res, next) { const pathname = req.path // 选择所需要缓存的路径,以首页为例 if (pathname === '/') { const existHtml = cachePage.get('index') if (existHtml) { return res.end(existHtml, 'utf-8') } else { // 重写res.end res.original_end = res.end res.end = function (data) { // 在发送页面数据的同时设置缓存 if (res.statusCode === 200) { cachePage.set('index', data) } res.original_end(data, 'utf-8') } } } next() } // nuxt.config.js // 将设置的缓存逻辑应用到服务端渲染中间件中 module.exports = { ... serverMiddleware: [ './pageCache' ], ... }
- 更新缓存
// server/index.js // 省略部分代码 const express = require('express') const app = express() const cachePage = require('../globalCache') async function start() { // 简略的做个刷新首页缓存的示例,将首页缓存置空 // 在服务端创建一个接口,在后端更新数据的同时,访问该接口刷新缓存 app.get('/refreshCache', (req, res, next) => { cachePage.set('index', null) res.sendStatus(200) }) ... }
优化效果
本地测试效果
- 缓存前的document下载的时间
- 缓存后的document下载时间
源码
存在的问题
- 该缓存方案只适用于与用户信息无关的页面,例如纯展示数据的页面等等。
- 缓存只生效于首屏页面,例如现在设置了second页面进行缓存,那么从首页跳转过去时,该缓存是无效的,只有直接打开second页面才有缓存的效果。具体原因可以看ssr的原理。
- 该缓存方案还可以应用在接口缓存与组件缓存当中,具体实现方案可以自己研究一下~