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開啓集羣模式去管理咱們的進程,從而知足更高的併發。