客户端渲染和服务端渲染详细执行流程
很早之前我就看过一些描述 SSR (server side render) 与 CSR (client side render)的文章,但在我自己去实现一套 SSR 以及将 SSR 与 CSR 作对比之前,我都没有深刻理解其中的区别,这里将以 Vue 为例,进行详细描述。
客户端渲染
CSR 是大家在使用 Vue 时最常用到的方式,Node 层可加可不加,也可以直接把打包后的文件扔到服务器上,通常使用 Webpack 打包之后的一个典型页面是这样的
1 |
|
为什么首屏慢?
在上面的例子中,浏览器在执行完 app.***.js
之前,,页面会一直显示空白,因为app.***.js
里是你所有的业务代码,包括 Vue 整个的实例化过程,其中就包括 挂载(mounted),而在没有挂载之前, id 为 app
的 Div 里是没有任何元素的。
所以在 manifest.***.js
, vendor.***.js
, app.***.js
这三个文件下载执行完之前,页面都会空白,这才导致白屏长,首屏慢,通常的做法是在 <div id="app"> </div
之前加一段 Loading,然后在获取到需要呈现的数据,条件”成熟”的时候(比如mounted)再去掉Loading,这样至少用户看上去不是白屏,但是首屏长的问题还是没法解决。
这里多说一句,将 Loading 加在 id 为 app
的元素里面反而更省事,因为 Vue 在第一次将生成好的 DOM 元素插入到 app
里的时候,是使用 innerHTML
的方式。
服务端渲染
SSR 是在 Vue2.0之后引入的,Node层是必须的。
首屏问题是如何被解决的
在 CSR 中,服务端返回的初始内容中,div#app
的内容为空,而在 SSR 中,返回的div#app
元素里却是不为空的,官网文档称之为 快照,是怎么回事呢?举个例子
1 |
|
1 | <template> |
通过上面的模板以及组件,通过 vue-server-renderer
编译之后,从Node端返回的HTML是这样的
1 |
|
这样的内容输出到客户端来,不必等到页面中的JS文件加载执行完,div#app
里也有内容,这才解决了首屏问题。
如果上面的 span
是一个输入框等随着用户操作而改变的元素,那此时的内容只是该元素变化过程中的一个临时状态,这就是 快照 的含义。
当然了,需要等到页面所有JS加载执行完,完成激活、挂载的操作,该元素才会变成随数据变化而变化的响应式元素。
服务端计算能力
CSR中,Vue的实例化、挂载都在用户侧浏览器(webview)里,作为天然的“分布式服务”,是不会有计算能力这个问题的,但是在SSR中,客户端只负责Vue实例的激活和挂载,而Vue实例是在服务端生成的,实例化过程中,需要生成 Virtual Dom
,这一步是非常消耗计算能力的,所以对于那些PV千万甚至上亿的服务来说,如果使用SSR,那Node服务器的CPU使用率,以及随之带来的时间消耗是需要特别注意的。