写点什么

聊一聊服务端渲染和客户端渲染

  • 2017-05-08
  • 本文字数:1846 字

    阅读完需:约 6 分钟

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

  • 能够为客户提供更理想的性能

  • 提供更为一致的 SEO 表现

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

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

理论性能收益

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

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

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

  • 尽管在 SSR 方面,页面会提前进行渲染以帮助客户更早查看页面内容,但在 React 真正执行完成之后,查看到的内容并无法进行交互。如果客户在此期间点击某按钮,该操作亦需要等待 React 执行完成后方可起效 ;

  • SSR TTFB(即第一字节时间)速度比 CSR 更慢,因为您的服务器需要耗费时间为页面创建 HTML,而非直接发送相对较空的响应内容 ;

  • SSR 的服务器数据吞吐量要远低于 CSR 数据通量。以 React 为例,这种数据吞吐量的差异将造成显著区别。ReactDOMServer.renderToString 为一项同步 CPU 绑定调用,其中包含该事件循环,意味着服务器将无法在 ReactDOMServer.renderToString 完成之前处理其它请求。这里我们假定您的页面需要 500 毫秒进行 SSR,则意味着您每秒至多只能执行 2 项请求。请千万重视这一情况

实际用例

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

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

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

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

Electrode 框架

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

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

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


感谢薛命灯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-05-08 19:005107
用户头像

发布了 24 篇内容, 共 97133 次阅读, 收获喜欢 7 次。

关注

评论

发布
暂无评论
发现更多内容

我是如何从零开始学Python:(2)如何解决安装和检查Python版本遇到的问题?

广之巅

Python 4月日更

重读《重构2》- 函数组合成变换

顿晓

重构 4月日更

Mac 新手使用技巧|从 Windows 换到 Mac,真没有想象中的那么难。

彭宏豪95

macos 效率 Mac windows 4月日更

算法训练营 - 学习笔记 - 第三周

心在飞

作业 - 分析一下微信朋友圈的高性能复杂度

sN0wpeak

架构实战营

架构实战营 模块二作业

ercjul

架构实战营

【架构实战营】第 2模块作业

swordman

架构实战营

【LeetCode】删除有序数组中的重复项Java题解

Albert

算法 LeetCode 4月日更

架构实践二

颜培攀

架构实战营

在JavaScript中使用对象来优化if/else和switch

devpoint

JavaScript 对象 Switch

有阳光的地方就会有影子

小天同学

公平 个人感悟 社会百态 4月日更

架构实战营 模块二 总结

Pitt

Ansible 安装

耳东@Erdong

ansible 4月日更

架构实战营 模块二

Keyto

架构实战营模块2作业

白发青年

架构实战营

架构实战营-M02H

赤色闪电

微信朋友圈架构设计

俞嘉彬

#架构实战营

Linux tail 命令

一个大红包

4月日更

朋友圈复杂度分析

鲲哥

一种特殊的树—堆

Nick

数据结构

架构实战营模块二作业

hunk

架构实战营

架构实战营 模块二 如何抓住架构设计的关键点

9527

rtsp系列专题(一)之rtsp服务器搭建

txp

音视频 音频技术

微信朋友圈架构设计

Vincent

#架构实战营

微信朋友圈 高性能分析

return

朋友圈高性能分析

^_^vincent

架构训练营模块二作业

Geek_e0c25c

架构训练营

架构实战营 - 模块 2- 作业

笑春风

模块二作业

梦寐凯旋

SQL 子查询怎么优化?写的很深的这种!

xcbeyond

sql SQL优化 4月日更

Golang interface and error handle

escray

学习 极客时间 Go 语言 4月日更

聊一聊服务端渲染和客户端渲染_语言 & 开发_Alex Grigoryan_InfoQ精选文章