nuxt
是基于vue
的ssr
解决方案,能够是使用vue语法完成先后端的同构。javascript
然而在与传统纯字符串拼接的ssr
方案相比,性能就没那么好了,nuxt
须要在服务端生成虚拟dom
,而后再序列化出HTML字符串,咱们常说nodejs
的高性能指的是异步IO操做频繁的场景而非CPU操做密集的场景,毕竟nodejs
是运行在单线程下的,在涉及到高并发的场景下,性能就会有所降低,能够考虑采用合理的缓存策略html
nuxt
的缓存能够分为组件级别缓存, API级别缓存以及页面级别缓存vue
配置项nuxt.config.js
的配置大概长这样子:java
const LRU = require('lru-cache')
module.exports = {
render: {
bundleRenderer: {
cache: LRU({
max: 1000, // 最大的缓存个数
maxAge: 1000 * 60 * 15 // 缓存15分钟
})
}
}
}
复制代码
并非说配了该项就实现了组件级别的缓存,还须要在需作缓存的vue
组件上增长name
以及serverCacheKey
字段,以肯定缓存的惟一键值,好比:node
export default {
name: 'AppHeader',
props: ['type'],
serverCacheKey: props => props.type
}
复制代码
上述组件会根据父组件传下来的type
值去作缓存,键值是:AppHeader::${props.type}
,由此,新的请求到来时,只要父组件传下来的type
属性以前处理过,就能够复用以前的渲染缓存结果,以增进性能ios
从该例子能够看出,若是该组件除了依赖父组件的type
属性,还依赖于别的属性,serverCacheKey
这里也要作出相应的改变,所以,若是组件依赖于不少的全局状态,或者,依赖的状态取值很是多,意味须要缓存会被频繁被设置而致使溢出,其实就没有多大意义了,在lru-cache
的配置中,设置的最大缓存个数是1000,超出部分就会被清掉git
其次,不该该缓存可能对渲染上下文产生反作用的子组件,好比,组件的created
与beforeCreated
的钩子在服务端也会走,组件被缓存后就不会执行了,这些可能影响到渲染上下文的地方也要当心,更多内容请参考:组件级别缓存github
通常来讲,比较适合的场景是v-for
大量数据的渲染,由于循环操做比较耗cpuaxios
在服务端渲染的场景中,每每会将请求放在服务端去作,渲染完页面再返回给浏览器,而有些接口是能够去作缓存的,好比,不依赖登陆态且不依赖过多参数的接口或者是单纯获取配置数据的接口等,接口的处理也是须要时间的,对接口的缓存能够加快每一个请求的处理速度,更快地释放掉请求,从而增进性能后端
api的请求使用axios
,axios
便可以在服务端使用也但是在浏览器使用,代码大概长这样子
import axios from 'axios'
import md5 from 'md5'
import LRU from 'lru-cache'
// 给api加3秒缓存
const CACHED = LRU({
max: 1000,
maxAge: 1000 * 3
})
function request (config) {
let key
// 服务端才加缓存,浏览器端就无论了
if (config.cache && !process.browser) {
const { params = {}, data = {} } = config
key = md5(config.url + JSON.stringify(params) + JSON.stringify(data))
if (CACHED.has(key)) {
// 缓存命中
return Promise.resolve(CACHED.get(key))
}
}
return axios(config)
.then(rsp => {
if (config.cache && !process.browser) {
// 返回结果前先设置缓存
CACHED.set(key, rsp.data)
}
return rsp.data
})
}
复制代码
使用上跟平时使用axios
仍是同样的,就多加了个cache
的属性标识是否须要在服务端作缓存
const api = {
getGames: params => request({
url: '/gameInfo/gatGames',
params,
cache: true
})
}
复制代码
在不依赖于登陆态以及过多参数的状况下,若是并发量很大,能够考虑使用页面级别的缓存, 在nuxt.config.js
增长serverMiddleware
属性
const nuxtPageCache = require('nuxt-page-cache')
module.exports = {
serverMiddleware: [
nuxtPageCache.cacheSeconds(1, req => {
if (req.query && req.query.pageType) {
return req.query.pageType
}
return false
})
]
}
复制代码
上面的例子根据连接后面的参数pageType
去作缓存,若是连接后面有pageType
参数,就作缓存,缓存时间为1秒,也就是说在1秒内相同的pageType
请求,服务端只会执行一次完整的渲染
nuxt-page-cache参考了route-cache,写得比较简陋,你也能够从新封装下,nuxt最终返回数据是使用res.end(html, 'utf-8')
,页面级别的缓存大概的思想以下:
const LRU = require('lru-cache')
let cacheStore = new LRU({
max: 100, // 设置最大的缓存个数
maxAge: 200
})
module.exports.cacheSeconds = function (secondsTTL, cacheKey) {
// 设置缓存的时间
const ttl = secondsTTL * 1000
return function (req, res, next) {
// 获取缓存的key值
let key = req.originalUrl
if (typeof cacheKey === 'function') {
key = cacheKey(req, res)
if (!key) { return next() }
} else if (typeof cacheKey === 'string') {
key = cacheKey
}
// 若是缓存命中,直接返回
const value = cacheStore.get(key)
if (value) {
return res.end(value, 'utf-8')
}
// 缓存原先的end方案
res.original_end = res.end
// 重写res.end方案,由此nuxt调用res.end其实是调用该方法,
res.end = function () {
if (res.statusCode === 200) {
// 设置缓存
cacheStore.set(key, data, ttl)
}
// 最终返回结果
res.original_end(data, 'utf-8')
}
}
}
复制代码
若是缓存命中,直接将原先的计算结果返回,大大提供了性能
在高并发的状况下能够考虑使用缓存,而缓存策略的使用须要视场景而定,这里再也不赘述,还能够考虑使用pm2开启集群模式去管理咱们的进程,从而知足更高的并发。