17611538698
webmaster@21cto.com

服务器端渲染和客户端渲染有什么区别?

资讯 0 3842 2017-05-08 12:01:28

485630_2f99_2.png

我们在walmart.com网站上的大多数页面采用服务器端渲染(简称SSR)方式。之所以选择服务器端渲染,主要出于以下两点考虑:

1、能够为客户提供更理想的性能
2、提供更为一致的SEO表现


正是由于SSR拥有上述优势,因此我们在将自有堆栈转换为React与Node.js时,投入了大量时间与精力以优化SSR性能。其中的一项关键性指标正在于页面内“明显位置”的渲染性能。我们发布的开源项目Electrode框架当中包含多种模块,能够有效提升SSR性能。
 
感兴趣的朋友可以点击下面链接参阅我之前发布的各模块助益评述。
https://medium.freecodecamp.co ... c3ab1

在发布Electrode框架并强调其面向SSR的设计思路之后,我收到了大量关于SSR优势的疑问与评论。在今天的博文中,我将专门探讨使用SSR在性能层面带来的改善效果——另外亦感谢Andrew Farmer与Patrick Hund在SEO优势评述方面提供的协助。
 
理论性能收益

首先我们将通过下面这份简单的时间线图展示SSR与CSR(即客户端渲染)之间的区别。
 

l1.png


l2.png

 

可以看到其中最大的区别在于,在使用SSR的情况下您的服务器对浏览器的响应结果属于已做好准备并可进行渲染的页面HTML,而CSR的浏览器响应结果则属于链接至您JavaScript的空文档。这意味着您的浏览器将立足服务器进行HTML渲染,而无需等待全部JavaSciprt代码的下载与执行。在这两种情况下,我们都需要下载React并利用同样的流程构建一个虚拟dom,而后附加各事件以实现页面交互——但在SSR方面,用户可在执行上述流程的同时查看到页面内容。而在CSR方面,大家则需要等待上述流程全部执行完成,而后方可进行查看。

现在,我们来了解以下注意事项:

1、尽管在SSR方面,页面会提前进行渲染以帮助客户更早查看页面内容,但在React真正执行完成之后,查看到的内容并无法进行交互。如果客户在此期间点击某按钮,该操作亦需要等待React执行完成后方可起效;
2、SSR TTFB(即第一字节时间)速度比CSR更慢,因为您的服务器需要耗费时间为页面创建HTML,而非直接发送相对较空的响应内容;
3、SSR的服务器数据吞吐量要远低于CSR数据通量。以React为例,这种数据吞吐量的差异将造成显著区别。ReactDOMServer.renderToString为一项同步CPU绑定调用,其中包含该事件循环,意味着服务器将无法在
4、ReactDOMServer.renderToString完成之前处理其它请求。这里我们假定您的页面需要500毫秒进行SSR,则意味着您每秒至多只能执行2项请求。
实际案例

在下图当中,我们就walmart.com网站上的各生产应用对SSR与CSR进行渲染效果比对。

l3.png


我们将三款应用(即主页、分类与搜索)分别立足SSR与CSR方式进行比较。相关结果来自Chrome浏览器所捕捉到的页面渲染时间指标。
 
大家可能已经注意到,SSR渲染速度要更快一些,而使用CSR则意味着加载过程中浏览器内将显示空白页面。大多数使用CSR的应用都会利用加载图标来取代这种难看的空白页面,但由于我们在正常操作中默认使用SSR,因此在CSR测试中页面仍保持未经发动的空白样式。需要注意的是,上述结果皆为我们的设备在一天中特定时段内配合实际生产配置捕捉到的结果,因此经过定制化调整的方案也许在性能上有所区别——不过总体而言,其仍然足以反映一般性趋势。

l4.png


上图为主页、分类与搜索页面的首次服务器响应对比。在这里我忽略掉了绿色指标条,因为其更多反映的是网络图中的其它元素。这里最值得关注的其实是文档大小与TTFB。
 
由于服务器会利用HTML对页面进行响应,因此大家可以看到SSR的文档总是相对较大。另外需要强调的是,正如前文中所提到,CSR响应速度更快(除了主页,这是因为受到本次测试中某些因素的影响)。

这里再次向大家强调,上述测量指标会随着应用类型、延迟、服务器、位置以及多种其它变量的变化而有所浮动,因此请不要将其视为科学的客观事实——而仅用于反映一种普遍规律。
 
Electrode框架

在我们对SSR与CSR进行A/B测试时,得出了以上总体趋势,而我们的数字也显示尽早进行渲染往往能够带来更理想的操作体验。

考虑到这些理由,我们的开源应用平台Electrode高度关注SSR。其默认启用SSR,而我们亦构建起多种模块以进一步提升SSR性能表现。感兴趣的朋友亦可点击此处参阅另一篇文章,我在其中展示了如何利用其中两款模块将RenderToString()时间缩短达70%。

这里再次感谢Mayakumar与Caoyang协助我审查并调整了本篇博文的具体内容。
 


作者|Alex Grigoryan编辑|薛命灯(聊聊架构公众号)
原文链接:https://medium.com/walmartlabs ... cefe8


评论