import LRUCache from 'lru-cache' import axios from 'axios' import globalConfig from '../../global-config' import createCacheKey from './createCacheKey' const cache = new LRUCache({ maxAge: 1000 * 60, // 有效期60秒,如果存在页面缓存,api缓存的时间应该比页面缓存的时间小,这样是为了让api响应的内容保持最新 max: 1000 // 最大缓存数量 }) /** * matchCacheCondition 是否满足持久化缓存条件:服务端运行时 && 非本地开发环境 && api请求为get请求方式 * @param {Object} config 请求配置 */ function matchCacheCondition(config = {}) { return process.server && process.env.NODE_ENV !== 'development' && config.method.toLowerCase() === 'get' } /** * 如果所有页面都启用了缓存,api缓存就没有必要了 */ export default function({ $axios, redirect }) { $axios.interceptors.request.use(config => { const { baseUrl } = globalConfig config.baseURL = baseUrl[process.env.environment] || baseUrl['other'] // 不满足缓存条件直接return config if (!matchCacheCondition(config)) { return config } const cacheKey = createCacheKey(config, true) const cacheData = cache.get(cacheKey) if (cacheData) { const source = axios.CancelToken.source() config.cancelToken = source.token source.cancel({ cacheData, cacheKey, url: config.url }) return config } return config }) $axios.interceptors.response.use(response => { if (matchCacheCondition(response.config)) { cache.set(createCacheKey(response.config), response) } return response }, (error) => { if (axios.isCancel(error) && matchCacheCondition(response.config)) { // console.log(`当前页面组件asyncData或者fetch函数中被缓存的接口url为:${error.message.url}`) return Promise.resolve(error.message.cacheData) } // 服务端打印api接口请求错误日志 if (process.server) { try { const { config: { url }, message } = error || {} console.log(`请求url:${url},错误消息:${message}`) } catch(error) { // console.log(error) } } // 服务端,客户端统一reject错误对象,因此页面组件asyncData,fetch函数请求api接口一定要做catch处理 return Promise.reject(error) }) }
3、组件缓存
vue官网文档原话:如果 renderer 在组件渲染过程中进行缓存命中,那么它将直接重新使用整个子树的缓存结果。这意味着在以下情况,你不应该缓存组件:
它具有可能依赖于全局状态的子组件。
它具有对渲染上下文产生副作用(side effect)的子组件。
因此,应该小心使用组件缓存来解决性能瓶颈。在大多数情况下,你不应该也不需要缓存单一实例组件。适用于缓存的最常见类型的组件,是在大的 v-for 列表中重复出现的组件。由于这些组件通常由数据库集合(database collection)中的对象驱动,它们可以使用简单的缓存策略:使用其唯一 id,再加上最后更新的时间戳,来生成其缓存键(cache key):
serverCacheKey: props => props.item.id + '::' + props.item.last_updated
4、页面组件asyncData函数优化
举一个简单的例子进行优化
{ async asyncData({ $axios }) { // 1、增加catch处理,是为了让服务端,客户端运行时不报错,特别是防止服务端运行时不报错,不然页面就挂了 // 2、catch函数返回一个resolve空字面量对象的Promise,表明dataPromise1的状态未来始终是resolved状态 const dataPromise1 = $axios.get('/api/data1').catch(() => Promise.resolve({})) const dataPromise2 = $axios.get('/api/data2').catch(() => Promise.resolve({})) const dataPromise3 = $axios.get('/api/data3').catch(() => Promise.resolve({})) const dataPromise4 = $axios.get('/api/data4').catch(() => Promise.resolve({})) const dataPromise5 = $axios.get('/api/data5').catch(() => Promise.resolve({})) const dataPromise6 = $axios.get('/api/data6').catch(() => Promise.resolve({})) const dataPromise7 = $axios.get('/api/data7').catch(() => Promise.resolve({})) const dataPromise8 = $axios.get('/api/data8').catch(() => Promise.resolve({})) // 保证apiData有数据 const apiData = await new Promise(resolve => { Promise.all([ dataPromise1, dataPromise2, dataPromise3, dataPromise4, dataPromise5, dataPromise6, dataPromise7, dataPromise8, ]) .then(dataGather => { resolve({ data1: dataGather[0], data2: dataGather[1], data3: dataGather[2], data4: dataGather[3], data5: dataGather[4], data6: dataGather[5], data7: dataGather[6], data8: dataGather[7], }) }) }) return apiData } }
二、node服务端错误检测,容错处理(提高node应用程序处理容错的能力)
首先确定使用nuxt.js框架,vue组件(页面/非页面组件)中以下函数都会在服务端执行,因此代码容错非常重要,函数代码执行一旦出错,页面就挂了
fetch
asyncData
beforeCreate
created
1、看的见的错误
看的见的错误是指在开发环境中,你只要在fetch等以上函数中js执行错误,本地就会有错误提示,便于你发现纠正错误代码逻辑
2、未知/看不见的错误(让未知错误暴露出来)