Vue SSR的渲染性能
一.前言
前端技术年年有新宠,Vue.js 2.0以其轻量级、渐进式、简洁的语法在MVVM框架中脱颖而出,一经推出便很受业界青睐。
为了提高首屏渲染速度 缓存+直出 是必不可少的。在Vue 1× 时代,没有 server-side-render 方案,直出需要专门给写一份首屏非Vue语法的模板。Vue2.0 server-side-render(简称Vue SSR)的推出,成功地让前后端渲染模板代码同构。
不过对于海量PV级的业务,直出模板的渲染效率直接影响服务端的压力,在对业务代码重构的同时,直出模板的性能是需要衡量的关键指标。
当前常用的模板渲染方案可以归结成两类:
a类:string-based (基于字符串拼接)
b类:virtual-dom-based(基于虚拟dom对象)
Vue SSR的模板是virtual-dom-based
二、常用string-based模板渲染原理介绍
还是先介绍下常用的string-based模板的写法和编译后的样子, 帮助不太熟悉HTML模板原理的同学可以更容易理解文章后面优化的过程。
首先看一下H5页面常用的HTML模板写法:

上面的模板应该是前端开发者很熟悉的一种模板语法,通过<%%>来包裹逻辑,<%=%>来赋值。
下面来看看模板代码被编译后的JS是什么样的:

JS中执行 tmpl.test(data) 即可拿到渲染出来的HTML片段。tmpl.test 就相当于是一个test模板的render函数。
那么这个render函数是如何通过上面的script模板转换过来的呢,此时需要一个模板的编译工具来实现,编译工具的核心是一个正则表达式:
let jscReg = new RegExp(/(?:(?:\r\n|\r|\n)\s*?)?<%([=-]?)([\w\W\r\n]*?)%>(?:\r\n|\r|\n)?/gmi);
用这个正则表达式,可以将模板代码中的 JS逻辑与JS属性值 分割出来,再通过'引号来将静态dom串包裹,拼接,最后加上函数的头尾,就能得到一个完整的render函数。编译过程可以通过预编译在线下实现,也可以在线上实时动态完成。
看到现在应该都理解了string-based HTML模板在JS中渲染的方式了吧,这种类型的模板渲染效率其实是最高的,因为它的render函数是不存在任何冗余逻辑,completely字符串拼接。
三、Vue SSR性能如何
实测循环 1w 次渲染耗时对比:
传统模板:143ms
Vue SSR:2685ms
Vue SSR的耗时是传统模板的近20倍
四、20倍差距是如何产生的?
20倍差距是如何产生的?我们来分析一下Vue SSR完整的渲染过程。
Vue模板片段:

Vue模板语法大部分都是指令试的伪代码,既不是HTML语法,也不是JS语法,这也是virtual-dom类模板渲染较复杂的原因之一。
步骤1:模板字符串通过正则解析成virtual-dom对象:

步骤2:生成with绑定上下文对象的render函数(该函数被缓存):

步骤3:_h ----> _createElement 执行render函数返回 包含了业务数据 的vnode对象:

步骤4:遍历dom对象属性 拼接字符串 HTML渲染完成:
四、性能瓶颈分析
在上文中可以看到,步骤1(模板字符串通过正则解析成virtual-dom对象)与步骤2(生成with绑定上下文对象的render函数)都已经被缓存,在本次对比中直接忽略其耗时,问题只能出在步骤3、4:
步骤3:执行render函数生成vnode-tree对象;
步骤4:递归遍历vnode-tree将其转化拼接成HTML;
相比传统string-based模板以最直接的方式拼接HTML,逻辑包含了 with、call、对象创建、递归拼接 是制约性能的关键,由于vnode对象是包含了业务数据,不能通过缓存vnode来解决,即便是缓存了vnode,步骤4的拼接耗时也是瓶颈所在。
五、缓存没有用,直接上大招!
既然我们已经知道什么样的render函数是最快的,那么就做个工具直接把Vue模板编译成string-based类的render函数即可,目标:

引入jscHelper https://github.com/jialunguo/vue-server-render-jscHelper
步骤1:
将vue-server-render在 第1步 生成的 virtual-dom对象 拼成 string-based语法的模板字符串,genEl是先将Vue模板语法转换成jsc语法:

1)值的转换

2)for循环转换

3)if判断转换

4)处理属性

5)Vue指令转换

6)样式class和内联代码转换

7)递归处理子dom

8)标签闭合

步骤2:
再通过文章开头介绍的正则表达式:
let jscReg = new RegExp(/(?:(?:\r\n|\r|\n)\s*?)?<%([=-]?)([\w\W\r\n]*?)%>(?:\r\n|\r|\n)?/gmi);
将模板编译成render函数,加以缓存。详细过程请看GitHub上的jscHelper源码。
七、写在最后
通过jscHelper对vue-server-render的性能做提升,需要持续地维护对Vue语法的兼容,而且目前并不支持类似, , 等高级语法,对组件的渲染方式也需要兼容。作为使用方,我们更希望Vue作者本身能多提供一种简单的string-based渲染方式来作为高性能的直出渲染方案。
相关的issue https://github.com/vuejs/vue/issues/5176 ,希望能在Vue.js未来版本中看到更好的渲染实现。
Vue SSR的渲染性能的更多相关文章
- Vue SSR 配合Java的Javascript引擎j2v8实现服务端渲染2创建Vue2+webpack4项目
前提 安装好nodejs并配置好环境变量,最好是 node10,https://nodejs.org/en/download/ 参考我之前的文章 debian安装nodejs Yarn &&a ...
- Egg + Vue 服务端渲染工程化实现
在实现 egg + vue 服务端渲染工程化实现之前,我们先来看看前面两篇关于Webpack构建和Egg的文章: 在 Webpack工程化解决方案easywebpack 文章中我们提到了基于 Vue ...
- Vue SSR不可不知的问题
Vue SSR不可不知的问题 本文主要介绍Vue SSR(vue服务端渲染)的应用场景,开发中容易遇到的一些问题,提升ssr性能的方法,以及ssr的安全性问题. ssr的应用场景 1.SEO需求 SE ...
- Vue SSR常见问题、异常处理以及优化方案
本文主要介绍Vue SSR(vue服务端渲染)的应用场景,开发中容易遇到的一些问题,提升ssr性能的方法,以及ssr的安全性问题. SSR的应用场景 1.SEO需求 SEO(Search Engine ...
- vue服务端渲染添加缓存
缓存 虽然 Vue 的服务器端渲染(SSR)相当快速,但是由于创建组件实例和虚拟 DOM 节点的开销,无法与纯基于字符串拼接(pure string-based)的模板的性能相当.在 SSR 性能至关 ...
- vue ssr
https://mp.weixin.qq.com/s/v1c69bJ5PxGcqt-ZU4FVXw https://juejin.im/entry/590ca74b2f301e006c10465f h ...
- webpack4+koa2+vue 实现服务器端渲染(详解)
_ 阅读目录 一:什么是服务器端渲染?什么是客户端渲染?他们的优缺点? 二:了解 vue-server-renderer 的作用及基本语法. 三:与服务器集成 四:服务器渲染搭建 4.1 为每个请求创 ...
- vue服务端渲染之nuxtjs
前言 本篇主要针对nuxtjs中的一些重要概念整理和代码实现! 在学习vue服务端渲染之前,先搞清楚几个概念: 什么是客户端渲染(CSR) 什么是服务端渲染(SSR) CSR和SSR有什么异同 客户端 ...
- Vue(服务端渲染)
一.前言 1.服务端渲染图解 2.简介服务端渲染 ...
随机推荐
- TableView,自定义TableViewCell
自定义Table 原理: http://blog.jobbole.com/67272/ http://www.cnblogs.com/wangxiaofeinin/p/3532831.html 补充: ...
- mac下的一些操作
mac 下修改Hosts文件 : http://www.cnblogs.com/zhangqs008/p/3773623.html mac下装Tomcat服务器: 在苹果系统安装Tomcat:首先下载 ...
- P4303 [AHOI2006]基因匹配 未完成
题目 luogu 暴力60pts部分 显然如果没有出现次数==5的条件 显然是\(N_{2}\)的求lcs的模板 但是加点条件就完全不同了 思路 这个题短小精悍,不想数据结构那么傻逼无脑 我们考虑一下 ...
- org.apache.axis2.AxisFault: java.lang.Error: Unresolved compilation problem:
原创:转载请注明出处 今天遇到以下一个异常,找了好长时间,就是不知道什么原因, 在网上搜了好多,也没搜到相关的解决方法. 1.异常展示, org.apache.axis2.AxisFault: jav ...
- SPOJ - HIGH Highways(矩阵树定理)
https://vjudge.net/problem/SPOJ-HIGH 题意: 给n个点m条边,求生成树个数. 思路: 矩阵树裸题. 具体的话可以看一下周冬的论文<生成树的计数及其应用> ...
- 数组类型的退化Decay
Decay即数组在某些情况下将退化为指针. 测试代码: #include <iostream> #include <typeinfo> template <typenam ...
- Qt加载OSg视图例子
//QT += core gui opengl //LIBS += -losgViewer -losgDB -losgUtil -losg -lOpenThreads -losgGA -losgQt ...
- [设计模式][C++]单例模式
参考:http://blog.csdn.net/hackbuteer1/article/details/7460019 单例模式意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有 ...
- ActivityGroup实现tab功能
android.app包中含有一个ActivityGroup类,该类是Activity的容器,可以包含多个嵌套进来的 Activitys,这篇文章就是借助ActivityGroup可以嵌套Activi ...
- 【Python】给图片添加水印的Python及Golang实现
前言 不知道大家有没有这样的习惯,一篇比较得意的博客在发表一段时间之后会特别关注,前段时间一篇写到凌晨的博客被 码迷 这个网关爬取之后发表了,因为搜索引擎先爬取码迷的,所以我的博客无法被搜索到,即使直 ...