博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nuxt渲染html文件,Nuxt页面级缓存
阅读量:6924 次
发布时间:2019-06-27

本文共 2444 字,大约阅读时间需要 8 分钟。

虽然 Vue 的服务器端渲染 (SSR) 相当快速,但是由于需要为每次请求为了避免交叉请求状态污染,都创建一个新的根Vue实例,创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接的模板的性能相当。在 SSR 性能至关重要的情况下,明智地利用缓存策略,可以极大改善响应时间并减少服务器负载。同时还可以大大减少后端接口服务器的负载。

在vue SSR指南中,缓存有两种,分为页面级缓存和组件级缓存。本次讲的是页面缓存,如果内容不是用户特定的并且在相对较短时间内,页面内容不需要更新。我们就可以使用页面缓存。对于页面级缓存我们可以通过这段koa服务器的代码大概知道缓存的思路:

const microCache = LRU({

max: 100,

maxAge: 1000 // 重要提示:条目在 1 秒后过期。

})

const isCacheable = req => {

// 实现逻辑为,检查请求是否是用户特定(user-specific)。

// 只有非用户特定 (non-user-specific) 页面才会缓存

}

server.get('*', (req, res) => {

const cacheable = isCacheable(req)

if (cacheable) {

const hit = microCache.get(req.url)

if (hit) {

return res.end(hit)

}

}

renderer.renderToString((err, html) => {

res.end(html)

if (cacheable) {

microCache.set(req.url, html)

}

})

})

复制代码

流程图如下:

a4980375636d0cc83464c2d17297fc24.png

上面的代码为vue的ssr渲染提供了方案,但是对于使用nuxt框架的同学而言,用脚手架初始化完,框架对于vue服务端渲染的res.end()函数做了高度封装,从下图nuxt在接收到请求后进行渲染的流程可以看出,nuxt主要是通过nuxtMiddleware调用renderRoute()来进行渲染的:

6aa09e646666d506eebae736d891b7ef.png

那么我们是否可以通过重写renderRoute()这个api拦截其内部渲染逻辑,在渲染之前加上缓存呢?nuxt-ssr-cache插件已经这样做了。我们来看一下这个nuxt模块核心部分的源码:

const renderer = nuxt.renderer;

const renderRoute = renderer.renderRoute.bind(renderer);

renderer.renderRoute = function(route, context) {

// hopefully cache reset is finished up to this point.

tryStoreVersion(cache, currentVersion);

const cacheKey = (config.cache.key || defaultCacheKeyBuilder)(route, context);

if (!cacheKey) return renderRoute(route, context);

function renderSetCache(){

return renderRoute(route, context)

.then(function(result) {

if (!result.error) {

cache.setAsync(cacheKey, serialize(result));

}

return result;

});

}

return cache.getAsync(cacheKey)

.then(function (cachedResult) {

if (cachedResult) {

return deserialize(cachedResult);

}

return renderSetCache();

})

.catch(renderSetCache);

};

复制代码

在这段代码中,先保存了renderer原来的renderRoute代码,之后又重写了renderRoute代码,返回了一个通过cache缓存来获取缓存内容的逻辑。cache返回了一个promise,如果是resolve的,并且有缓存的内容,就直接返回缓存内容。如果没有缓存内容或者reject,就执行renderSetCache()。而renderSetCache()中,返回了原来最初的renderRoute()处理逻辑,同样如果renderRoute()返回的promise被resolve了,那么就通过cache的setAsync方法来进行缓存,之后返回渲染结果。

使用方法大家自行参考git中的readme文档,这里就不说了。

下面我们真正来仿真一下,看看这个模块的功效到底如何。我们通过ab命令

ab -n 4000 -c 50 -s 120 -r http://localhost:3000/

复制代码

来进行压测:

第一种情况,没有添加页面缓存,大约持续请求了10秒钟,执行到3600个请求的时候,发生错误,不再继续请求了:

afcd57bb78052669d80e7cd43b386549.png

我们来通过日志看下是什么错误:

1297b98dc43661971bd6bc45718f2583.png

可以看到FATAL ERROR这一句,JavaScript heap out of memory。堆内存已经没有办法再进行分配,所以进程终止了。

我们在终止之前通过进程监视器可以看到node进程已经彪到了1.7GB的内存。

001d8e8e9fdc5a94dc377f0da41f9bf8.png

第二种情况,我们添加了页面缓存,通过server端的日志,我们可以看出,只请求了一次后端的api数据接口,说明缓存已经成功拦截了页面请求。请求数据如下:

5d613d4075891aae11052c7074e0934b.png

在2秒钟之内,就顺利结束了4000个请求,内存没有任何明显波动,优化效果显而易见。

更多精彩文章请关注公众号:

转载地址:http://zodjl.baihongyu.com/

你可能感兴趣的文章
FluentData官方文档翻译
查看>>
Hanlp中使用纯JAVA实现CRF分词
查看>>
代码快速“检”“修”不是梦,阿里云MaxCompute Studio 2.9.0 新版本发布
查看>>
Why Redis 4.0?
查看>>
centos 5.6 挂载ntfs
查看>>
TCP/IP协议三次握手流程
查看>>
vsftpd的工作原理和配置
查看>>
Matches Puzzle Game
查看>>
RedHat Squid 正向代理
查看>>
关闭redhat蜂鸣音
查看>>
OSPF 高级实验
查看>>
ADS(供选数据流)隐藏
查看>>
myisam和innodb读写性能对比
查看>>
Android使用jni
查看>>
Apache Camel
查看>>
大数据Java基础第五天作业
查看>>
Java面向对象之多态
查看>>
mysql常用语句总结
查看>>
Ubuntu 禁止Guest用户登陆
查看>>
第一步基本完成---md之crystal转为C
查看>>