很早之前我就看过一些描述 SSR (server side render) 与 CSR (client side render)的文章,但在我自己去实现一套 SSR 以及将 SSR 与 CSR 作对比之前,我都没有深刻理解其中的区别,这里将以 Vue 为例,进行详细描述。

客户端渲染

CSR 是大家在使用 Vue 时最常用到的方式,Node 层可加可不加,也可以直接把打包后的文件扔到服务器上,通常使用 Webpack 打包之后的一个典型页面是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="//path/to/app.***.css">
</head>
<body>
<div id="app"></div>
<script scr="//path/to/manifest.***.js"></script>
<script scr="//path/to/vendor.***.js"></script>
<script scr="//path/to/app.***.js"></script>
</body>
</html>

为什么首屏慢?

在上面的例子中,浏览器在执行完 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
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
1
2
3
4
5
<template>
<div>
<span>{{msg}}</span>
</div>
</template>

通过上面的模板以及组件,通过 vue-server-renderer 编译之后,从Node端返回的HTML是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="//path/to/app.***.css">
</head>
<body>
<div id="app" data-server-rendered="true">
<span>this is msg</span>
</div>
<script scr="//path/to/manifest.***.js"></script>
<script scr="//path/to/vendor.***.js"></script>
<script scr="//path/to/app.***.js"></script>
</body>
</html>

这样的内容输出到客户端来,不必等到页面中的JS文件加载执行完,div#app里也有内容,这才解决了首屏问题。

如果上面的 span 是一个输入框等随着用户操作而改变的元素,那此时的内容只是该元素变化过程中的一个临时状态,这就是 快照 的含义。

当然了,需要等到页面所有JS加载执行完,完成激活、挂载的操作,该元素才会变成随数据变化而变化的响应式元素。

服务端计算能力

CSR中,Vue的实例化、挂载都在用户侧浏览器(webview)里,作为天然的“分布式服务”,是不会有计算能力这个问题的,但是在SSR中,客户端只负责Vue实例的激活和挂载,而Vue实例是在服务端生成的,实例化过程中,需要生成 Virtual Dom,这一步是非常消耗计算能力的,所以对于那些PV千万甚至上亿的服务来说,如果使用SSR,那Node服务器的CPU使用率,以及随之带来的时间消耗是需要特别注意的。