亲宝软件园·资讯

展开

Nuxt 项目性能优化调研

lessfish 人气:1
性能优化,这是面试中经常会聊到的话题。我觉得性能优化应该因具体场景而异,因不同项目而异,不同的手段不同的方案并不一定适合所有项目,当然这其中不乏一些普适的方案,比如耳熟能详的文件压缩,文件缓存,CDN,DNS 预解析,等等,但是我更希望听到的是因为不同的项目不同的需求,解决不同的问题而采取的不同的优化手段,比如 BigPipe,分段输出页面的各个部分,对于 SNS 网站是非常合适的,减少了用户的等待时间;相对应的还有一个 BigRender,这是一个大的延迟加载,360 导航首页目前还在使用,京东淘宝首页也是这个思路,对于一些类门户网站非常适用,但是如果你的网页内容不是非常多,就没有必要了 今天要说的是 Nuxt。Nuxt 是支持 Vue SSR 的一个框架,底层需要运行 Node 服务。大概描述一下 Vue 的渲染过程,首先每个组件都会被编译生成一个渲染函数(这部分基本 webpack 打包已经做掉),然后渲染函数生成虚拟 dom,最后虚拟 dom 通过 patch 方法将真实 dom 渲染到页面上。Nuxt 其实就是将这部分放到了服务端去做,在服务端拿到渲染页面所需要的 html,从而使得 html 能够直出,**而客户端其实还是会运行整个 Vue 的生命周期**,这就带来了一个问题,**这部分操作放在了服务端其实是非常耗 cpu 的**,创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接的模版的性能相当,如果是不加优化的 Nuxt 项目,高并发下是很脆弱的,毕竟 Node 运行在单线程下,不适合 cpu 操作密集型的场景 使用 Nuxt 的项目无非看中了它的两大优点,一是服务端渲染满足 SEO 的需求,二是首屏直出比 SPA 快,再加上如果如果公司是 Vue 系,使用 Nuxt 就更顺理成章。但是不要忘了性能,高并发下 Nuxt 性能确实不乐观,我测试了官网的 hackernews demo 项目,2 核 cpu + 4g 内存,400 并发下它的吞吐量不超过 50,就算是最简的 Nuxt 项目,吞吐量也就 300+,这就说明如果项目不做缓存,300+ 已经是最大的吞吐量了,而最小 express demo 可以轻松到 3000,这就决定了高流量项目并不会轻易去使用 Nuxt 我们的项目目前其实是一个不加优化的 Nuxt 项目,因为用户不多,平时并没有什么问题,但是一到展会,就会有不少用户同时访问,反馈页面会很卡。同条件下做了压测后,吞吐量也是 50 上下,平均响应时长七八秒,所以卡是正常现象 看了一下项目代码,发现了几个问题: 1. 项目没做缓存,所以每次访问都会经历所有 Nuxt 生命周期,消耗 cpu,这点是最致命的 2. 项目打包默认 gzip。Nuxt 项目打包会默认在服务端开启 gzip,因为我们网关层已经做了 gzip,所以这里是不必要的,测试了下关掉 gzip 吞吐量和响应时间都能提高 20% 左右 3. API 请求比较乱。很多请求并没有很好地区分客户端和服务端,而是都由服务端去做了,造成服务端压力过大,其实多数和用户有关的请求理应放到客户端。有的接口为了方便,一次性返回了所有内容,也没有做客户端/服务端区分。另外,服务端的接口请求可以并发,用类似 Promise.all 的形式去控制 4. SEO。有的内容页面,很长,有五个部分,除了内容外,还有猜你喜欢等其他部分,询问了 SEO 同事,说这几部分都是需要 SEO 的,我不是很懂 SEO,但是在我看来,ssr 只应该渲染首屏内容,而 UI 在设计的时候应该把主要内容设计到首屏,从而满足 SEO 对此我觉得可以从两个方向去优化: 1. 缓存。缓存是最重要的方案,针对 Nuxt 项目可以做三级缓存,页面缓存、组件缓存以及 API 缓存。页面缓存是最重量级的缓存方案,能不能做页面缓存可以从以下两个点判断: * 同一个 URL,对于 登录 / 非登录 用户,服务端渲染的内容是相同的(注意是服务端渲染内容,而非前端) * 同一个 URL,对于不同的登录用户,服务端渲染的内容是相同的,即没有一些个性化的渲染(常见的个性化渲染,比如针对不同用户渲染不同的猜你喜欢内容等) 其实也就是返回的 html 代码相同就好,主要关注下返回的全局 store 是否一致,另外也不能做一些服务端才能做的操作,比如 set-cookie 等 2. 控制好首屏模块个数,对返回的结果进行精简,最小化,保证吐出到浏览器的内容足够小。这就是前面说的并不要对所有模块都做 ssr,需要首屏呈现的/需要爬虫爬的,我们直出,其他部分做 CSR 就行了 而我们的网站大部分页面是满足做页面缓存条件的,测试了下如果做页面缓存,吞吐量能到 500+,这个数据这个时候其实是和页面大小有关系了,页面缓存的性能是能满足需求的。而有另一类页面,相同的 URL 会返回不同的内容,而且整页都是不同内容,它的实现是获取 cookie 中的不同 city-id,渲染不同城市的内容,很显然这部分页面做不了页面缓存了,API 缓存和组件缓存理论上都是可以试试的 做缓存优化,至少需要访问一次,第二次才能生效,那么还有另一种情况,对于这样的路由 `/store/:id`,并发打开 id 0~1000,很显然每个页面都是不一样的店铺数据,并不能命中缓存(可能命中组件缓存,暂时忽略),这个时候只能从 Nuxt 生命周期上去优化了,那么以上方向的第二点,控制首屏模块个数就能用到了。所以本文一开始我就说,不同的方案是适配不同的场景的,解决不同的问题会采取不同的手段

加载全部内容

相关教程
猜你喜欢
用户评论