【Nuxt】03 Nuxt2 页面缓存、组件缓存、api缓存

基于nuxt.js的服务端渲染项目可以通过缓存来优化的场景有以下几点:

优化点参考文档及思路优化场景/条件特别说明检测方法
1. 页面缓存vue官方文档页面内容不是用户特定(即对于相同的 URL,总是为所有用户渲染相同的内容)一般来说,一个页面在服务端做了持久化缓存,那么对应页面的存在的api缓存,组件缓存也就没有意义了,对于页面缓存与api缓存同时存在的情况下(有可能存在),api缓存的时间应该比页面缓存的时间小,这样是为了让api响应的内容保持最新1、代码本地测试:在asyncData中打印测试日志,页面缓存后,刷新页面后服务端不会输出测试日志;2、比较html页面加载的DOMContentLoaded时间,刷新页面可以看到缓存后的值比首次页面加载(未缓存)的值要小
2. api缓存在axios请求与响应拦截器中去做接口响应内容不是用户特定(即对于相同的api接口URL,即总是为所有用户响应相同的内容)一般请求方式为GET的api请求比较首次请求与缓存后的api接口响应的时间
3. 组件缓存nuxtjs官网文档 vue 官网文档不依赖与全局状态,对渲染上下文不产生副作用的子组件要缓存的组件name值必须唯一,serverCacheKey根据某个prop的值作为唯一key检测方法同页面缓存检测方法一致,这个可能几乎察觉不到
4. asyncData函数优化Promise.all该函数中请求api接口数超过1个,多的甚至达到10,20多个,这种情况我们不能使用async await,请求完一个再接着请求下一个(同步请求接口);如果有10个接口需要请求,每个接口平均响应1s,那么至少需要10s才会响应html页面;如果使用Promise.all异步请求10个接口,那么最快接近1s响应html页面;asyncData函数会在服务端执行代码,因此一定要做好容错处理;另外如果该函数代码一直未执行完,那么页面首次响应将会被挂起,一直处于加载中对于页面首次加载,该函数执行耗时越短,页面响应时间就越短(页面加载越快)

1、页面缓存功能模块实现

我们在项目根目录中创建一个文件 ~/serverMiddleware/page-cache.js

import LRUCache from 'lru-cache'const cache = new LRUCache({maxAge: 1000 * 60 * 2, // 有效期2分钟max: 1000 // 最大缓存数量
})export default function(req, res, next) {// 本地开发环境不做页面缓存if (process.env.NODE_ENV !== 'development') {try {const cacheKey = req.urlconst cacheData = cache.get(cacheKey)if (cacheData) {return res.end(cacheData, 'utf8')}const originalEnd = res.endres.end = function(data) {cache.set(cacheKey, data)originalEnd.call(res, ...arguments)}} catch(error) {// console.log(`page-cache-middleware: ${error}`)next()}}next()
}

2、api缓存功能模块实现

我们在项目根目录中分别创建两个文件 ~/plugins/axios/createCacheKey.js 与 ~/plugins/axios/cache.js ;特别坑的一点是nuxt.js开发环境cache.js插件代码在页面刷新,路由切换都相当于首次运行,因此你会发现缓存功能失效,只有在 process.env.NODE_ENV === ‘production’ 生产环境中测试有效

// ~/plugins/axios/createCacheKey.jsimport md5 from 'md5'/*** 根据请求配置,是否是请求拦截器 创建缓存key* @param {Object} config* @param {Boolean} isRequest */export default function createCacheKey(config = {},isRequest = false
) {const {url,data,params,method,baseURL,} = config || {}let commonUrl = url/*** request拦截器中config.url是未拼接baseURL的,response拦截器中response.config.url是拼接过baseURL的,* 为了保持统一,使用统一拼接baseURL的commonUrl;注意下面的if条件判断*/if (isRequest && !commonUrl.match(baseURL) && !commonUrl.match(/^https?/)) {commonUrl = !!baseURL.match(/.+\/$/) ? `${baseURL.replace(/\/$/, '')}${url}` : `${baseURL}${url}`}// 根据请求指令,url,body体,参数生成规则const rule = `method=${method}-url=${commonUrl}-data=${JSON.stringify(data || {})}-params=${JSON.stringify(params || {})}`// md5加密return md5(rule)
}
// ~/plugins/axios/cache.js
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 } = globalConfigconfig.baseURL = baseUrl[process.env.environment] || baseUrl['other']// 不满足缓存条件直接return configif (!matchCacheCondition(config)) {return config}const cacheKey = createCacheKey(config, true)const cacheData = cache.get(cacheKey)if (cacheData) {const source = axios.CancelToken.source()config.cancelToken = source.tokensource.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):
const LRU = require('lru-cache')
module.exports = {render: {bundleRenderer: {cache: LRU({max: 1000, // 缓存队列长度maxAge: 1000 * 60 // 缓存1分钟})}}
}

需要做缓存的 vue 组件, 需增加 name 以及 serverCacheKey 字段,以确定缓存的唯一键值。


export default {name: 'zzZyHome',props: ['type'],serverCacheKey: props => props.type + '::' + 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}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149076.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Modelsim测试覆盖率操作说明

1、打开Project窗口界面 2、在project界面下,选中所有需要测试覆盖率的.v文件(不包括tb文件),鼠标点击右键,在Properties选项中选择Coverage选项,选择需要测试的覆盖率类型 3、重新编译所有的源文件&#x…

(三) Markdown插入互联网或本地视频解决方案

前言 不论博客系统是WordPress还是Typecho,绕不开的是两种书写语言,一种称之为富文本,一种叫做Markdown。 Markdown有很多好处,也有很多坏处,比如Markdown本身不具备段落居中的功能,以及Markdown也不具有…

Java架构师职责和技能

目录 1 架构师简介2 架构师职责2.1 架构师是技术领导架构设计做决策2.2 架构师可以是团队或者组织2.3 架构师必须掌握足够的技术知识2.4 架构师必须掌握足够的架构设计技能2.5 架构师必须具备很好的编程能力2.6 架构师必须深入理解业务及其业务的领域知识2.7架构师应该具备很好…

基于Java的驾校收支管理可视化平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

二层VLAN配置实验

四台PC的IP地址如图所示,子网掩码均为255.255.255.0,四台PC处在同一个局域网之中,在配置VLAN之前能够彼此ping通。配置的目的是将PC1和PC3划分到VLAN10中,PC2和PC4划分到VLAN20中。 在配置之前需要进入系统视角。 创建VLAN 在两…

设计加速!11个Adobe XD插件推荐!

你是否一直在寻找可以提升 Adobe XD 工作流程和体验的方法?如果是,一定要试试这些 Adobe XD 插件!本文将介绍 11 款好用的 Adobe XD 插件,这些插件可以为 UI/UX 设计添加很酷的新功能,极大提升你的工作效率和产出。让我…

SQL与关系数据库基本操作

SQL与关系数据库基本操作 文章目录 第一节 SQL概述一、SQL的发展二、SQL的特点三、SQL的组成 第二节 MySQL预备知识一、MySQL使用基础二、MySQL中的SQL1、常量(1)字符串常量(2)数值常量(3)十六进制常量&…

论文学习:RT-DETR

RT-DETR 摘要 DETR取得显著性能,但高成本计算使其无法发挥无NMS的优势,无法实际应用。本文分析了NMS对准确性和速度的负面影响,并建立端到端的速度基准。第一个实时端到端检测器,高效处理多尺度特征,并提出IoU-aware…

osgPBR(十五)镜面IBL--查看不同级别的HDR环境贴图

首先&#xff0c;设置可以使用Mipmap&#xff0c;启用三线性过滤&#xff0c;设置最大级别和最小级别 osg::ref_ptr<osg::TextureCubeMap> tcm new osg::TextureCubeMap; tcm->setTextureSize(128, 128);tcm->setFilter(osg::Texture::MIN_FILTER, osg::Texture:…

《幸福之路》罗素(读书笔记)

目录 作者简介 作者的感悟 经典摘录 一、不幸福的成因 1、一部分要归咎于社会制度 2、一部分则得归咎于个人心理——当然&#xff0c;你可以说个人心理是社会制度的产物。 二、欠缺某些想要的东西&#xff0c;是快乐的必要条件 三、无聊与刺激 四、现代人的精神疲劳 五…

【C++】vector相关OJ

文章目录 1. 只出现一次的数字2. 杨辉三角3. 电话号码字母组合 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)&#xff89;" 1. 只出现一次的数字 力扣链接 代码展示&#xff1a; class Solution { public:int singleNumber(vector<i…

【“栈、队列”的应用】408数据结构代码

王道数据结构强化课——【“栈、队列”的应用】代码&#xff0c;持续更新 链式存储栈&#xff08;单链表实现&#xff09;&#xff0c;并基于上述定义&#xff0c;栈顶在链头&#xff0c;实现“出栈、入栈、判空、判满”四个基本操作 #include <stdio.h> #include <…

大数据-玩转数据-Flink SQL编程实战 (热门商品TOP N)

一、需求描述 每隔30min 统计最近 1hour的热门商品 top3, 并把统计的结果写入到mysql中。 二、需求分析 1.统计每个商品的点击量, 开窗2.分组窗口分组3.over窗口 三、需求实现 3.1、创建数据源示例 input/UserBehavior.csv 543462,1715,1464116,pv,1511658000 662867,22…

基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度(matlab代码)

目录 1 主要内容 系统结构图 P2G-CCS 耦合模型 其他算例对比 2 部分代码 3 下载链接 1 主要内容 该程序复现《基于阶梯碳交易的含P2G-CCS耦合和燃气掺氢的虚拟电厂优化调度》模型&#xff0c;以碳交易和碳封存成本、燃煤机组启停和煤耗成本、弃风成本、购气成本之和为目标…

vertx的学习总结6

Beyond the event bus 一、章节覆盖&#xff1a; 如何在事件总线之上公开服务 verticles和事件总线服务的异步测试 动态代理&#xff1a; MyService 接口 package porxy.test;import io.vertx.codegen.annotations.ProxyGen;ProxyGen public interface MyService {void he…

智慧公厕:城市公共厕所的未来之路

随着城市化进程的不断推进&#xff0c;人们对城市环境质量的要求也越来越高。在城市管理中&#xff0c;公厕作为一个必不可少的公共设施&#xff0c;不仅关乎城市的文明形象&#xff0c;还与市民的生活质量密切相关。为了解决传统公厕存在的问题&#xff0c;智慧公厕应运而生。…

Go-Python-Java-C-LeetCode高分解法-第八周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 我搜集到了50道精选题&#xff0c;适合速成概览大部分常用算法 突…

大模型部署手记(3)通义千问+Windows GPU

1.简介 组织机构&#xff1a;阿里 代码仓&#xff1a;GitHub - QwenLM/Qwen: The official repo of Qwen (通义千问) chat & pretrained large language model proposed by Alibaba Cloud. 模型&#xff1a;Qwen/Qwen-7B-Chat-Int4 下载&#xff1a;http://huggingface…

【AI视野·今日Sound 声学论文速览 第十八期】Wed, 4 Oct 2023

AI视野今日CS.Sound 声学论文速览 Wed, 4 Oct 2023 Totally 4 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers Mel-Band RoFormer for Music Source Separation Authors Ju Chiang Wang, Wei Tsung Lu, Minz Won最近&#xff0c;基于多频段频谱图的方法…

windows server 2012 服务器打开系统远程功能

服务器上开启远程功能 进入服务器&#xff0c;选择“添加角色和功能” 需要选择安装的服务器类型&#xff0c;如图所示 然后在服务器池中选择你需要使用的服务器。 选择完成后&#xff0c;在图示列表下勾选“远程桌面服务” 再选择需要安装的功能和角色服务。 选择完成确认内容…