石器时代:传统 MPA
最初的网页
1991年,蒂姆·伯纳斯·李在欧洲核子研究组织创造了世界上第一个网页。
那时候没有人知道这会改变世界。这个网页就像一份静态文档,地址是 info.cern.ch/hypertext/W… 。
那时候的网页就像一本电子书。服务器只做一件事:把写好的 HTML 文件发给浏览器。没有交互,没有动态内容,每个访问者看到的内容都一模一样。
缺点很明显
那时候的前端工程师(如果有的话)面临的问题是:
-
每次都要重新加载:点个链接就要刷新整个页面,用户体验很差。这在现代网站中简直不可想象。
-
没有交互:网页就是一个静态的富文本容器,无法响应用户的操作。
-
太单调了:所有访问者看到的内容都一样,无法根据用户做出个性化的调整。
三个救世主的出现
为了解决这些问题,三个关键的技术陆续出现了。他们就像三个救世主,彻底改变了网页的未来。
JavaScript (1995年):十天的奇迹
网景公司的浏览器 Navigator 发布后,他们面临了一个问题:怎么让网页能动起来?
他们需要一种网页脚本语言。
1995年,网景公司的 Brendan Eich 迫于公司的压力,做了一个疯狂的决定:只花十天就设计了 JavaScript 的最初版本。
十天。
一个影响了全世界几十年的编程语言,就是在十天内设计出来的。
最初他们叫它 Mocha。后来为了蹭 Java 的热度(Java 那时候很火),改名为 JavaScript。实际上,网景公司和 Sun 公司结成联盟,才最终改名为 JavaScript。
有趣的是,JavaScript 和 Java 其实没什么关系。就像雷锋和雷峰塔一样。
最初,JavaScript 只是用来做一些简单的事情:表单验证、文字跑马灯、简单的动效。但它打开了一扇门——网页终于可以动起来了。
CSS (1996年):美学的胜利
HTML 诞生以来,网页基本上就是一个简陋的富文本容器。
早期网页流行用 table 标签进行布局。你没看错,就是用表格来做网页布局。这简直是一场灾难。
那时候的设计师一定有多绝望。
为了解决网页"丑"的问题,Hkon Wium Lie 和 Bert Bos 共同起草了 CSS 提案。W3C 对这个很感兴趣,最后在 1996 年 12 月推出了 CSS 规范的第一版本。
CSS 的出现让网页设计变成了一门艺术。网页终于不用再靠 table 布局了。
1999年的 Apple store:
Ajax (1998年-2005年):等待的七年
1998年,微软的 Outlook 邮件团队利用客户端脚本实现了第一个 XMLHTTP 组件。
但这个技术并未引起广泛关注。
没人在意。
直到 2005 年,谷歌通过 Gmail 和 Google Maps 等产品展示了 Ajax 的强大功能,它才成为主流技术。
第一次用 Gmail 时,可以在不刷新页面的情况下发送邮件。第一次用 Google Maps 时,可以在不刷新页面的情况下拖动地图。那种感觉就像魔术一样。
Ajax 的意义在于:网页终于可以在不刷新的情况下,偷偷跟服务器要数据了。
适用场景
优势:
-
使用局限性小,支持动态数据
-
在服务端数据获取快的情况下,首屏性能好
-
SEO 友好(因为服务器直接返回完整的 HTML)
不足:
-
需要后端模板技术(如 JSP、PHP、Django 模板),前后端耦合严重
-
开发和维护成本高
-
用户体验不如现代的 SPA
适用场景: 有后端团队、无专职前端、对体验要求不高的小团队。
文艺复兴:SPA 的崛起
一个转折点
大概在 2015-2016 年左右,前端开发的方式开始发生变化。
那时候的网页开发就是这样的:写 HTML,写 CSS,写一点 JavaScript。然后后端同学写 PHP 或者 Java,在模板里插一些数据。
前后端混在一起,代码乱得一塌糊涂。
然后 Angular.js 出现了。
Angular.js:第一个真正的 SPA 框架
Angular.js 的出现就像一道闪电,照亮了前端的未来。
这是第一个真正的 SPA (单页应用) 框架。
它带来了什么?
-
客户端 MVC 架构:把代码分成 Model、View、Controller,结构清晰。
-
双向数据绑定:改变数据,视图自动更新;改变视图,数据自动更新。
-
模板系统:在 HTML 中直接写逻辑,不需要后端模板引擎。
-
依赖注入:代码更容易测试和维护。
这是一场革命。网页开发从此变成了客户端应用开发。
第一次用 Angular.js 的时候,那种感觉就像从黑白电视进入了彩色电视的时代。
React, Vue, Angular:三国争霸
接着就是我们熟悉的"三国争霸":
-
React (2013):Facebook 开源,虚拟 DOM,组件化,学习曲线陡峭但生态强大。
-
Vue (2014):尤雨溪开源,易学易用,中文文档完善,国内最受欢迎。
-
Angular (2016):Google 推出的 Angular 2,完全重写,企业级框架。
这三个框架各有特点,但核心思想都一样:把网页开发变成了组件开发。
很多开发者从 jQuery 时代转向 React 时代,那种转变就像学会了一种新的思维方式。
SPA 的渲染流程
这个过程中,浏览器要等 JavaScript 下载、解析、执行完,才能开始渲染页面。
SPA 的优势
-
体验好:页面切换流畅,像在用一个桌面应用,没有刷新的感觉。
-
前后端分离:前端只管做交互,后端只管提供 API,各干各的,很清爽。
-
部署简单:前端就是一堆静态文件,扔到 CDN 上就行。
-
运营成本低:不需要养一台专门的服务器。
那时候的兴奋难以名状。前端终于可以独立了。不再依赖后端的模板引擎,不再等后端同学部署代码。
前端的春天来了。
SPA 的问题
但春天很短。
首屏慢
浏览器得先下载一个巨大的 JavaScript 文件(现代 SPA 的 bundle 经常超过 1MB),然后才能开始画页面。
时间轴:
0ms ├─ 请求 HTML (快)
100ms ├─ 下载 JS (慢)
500ms ├─ 解析 JS (慢)
800ms ├─ 执行 JS (慢)
1000ms ├─ 发起 API 请求 (慢)
1500ms ├─ 获取数据 (慢)
2000ms └─ 页面渲染完成 (太慢了!)
太多电商网站都经历过这种尴尬:用户搜索"手机壳"进来,结果页面白屏 2 秒钟。用户早就关掉了。
SEO 不友好
搜索引擎的爬虫过来一看,你的 HTML 是空的,啥也看不到。所以你的网站在搜索结果里排名很低。
有个内容网站,文章质量很高,但因为采用 SPA,搜索引擎无法索引,流量从何而来?
一个尴尬的时刻
大概在 2015-2016 年,前端社区开始意识到一个问题:
我们为了追求"完美的客户端体验",牺牲了"首屏性能"和"SEO"。
这不是一个好的权衡。
工业革命:SSR 和同构应用
问题的出现
SPA 很爽,但首屏慢和 SEO 不友好这两个问题,对某些场景来说是致命的。
Airbnb 面临了这个问题。
Airbnb 的探索
Airbnb 是一个全球性的平台。他们的网站需要被全世界的搜索引擎索引。
但他们用的是 React,一个 SPA 框架。
他们想,能不能让 React 代码在服务器上也跑一遍,直接生成带内容的 HTML?
这个想法催生了"同构" (Isomorphic) 应用的概念。
简单说就是:同一份 JavaScript 代码,既能在浏览器上跑,也能在服务器上跑。
这是一个超前的想法。
水合 (Hydration)
React 团队在进行同构应用的探索中,提出了"水合"的概念。
这个过程就像:服务器先把网页的骨架画好给你,浏览器拿到手再把血肉(事件绑定、状态)填上。
"水合"这个概念很形象。就像一个干枯的骨架,被水浸润后,重新活了过来。
SSR 的优势
-
首屏快:用户能更快地看到内容。
-
SEO 友好:搜索引擎能爬到完整的 HTML。
-
统一的心智模型:不需要学习额外的后端模板技术,用 React/Vue 就能搞定。
-
容灾完备:在服务端出现故障后,通常可以降级到 CSR 渲染模式。
SSR 的问题
但问题也来了,而且很复杂。
首屏可能还是慢
如果页面上有一个接口很慢,服务器就得一直等着,直到所有数据都准备好了才能返回 HTML。
[配图:SSR 首屏时间瀑布图]
时间轴:
0ms ├─ 请求 HTML
100ms ├─ 服务器处理请求
200ms ├─ 发起 API 请求 (快的接口)
200ms ├─ 发起 API 请求 (慢的接口)
400ms ├─ 快的接口返回
500ms ├─ 等待慢的接口... (一直在等)
1000ms ├─ 慢的接口终于返回
1100ms ├─ 服务器生成 HTML
1200ms └─ 浏览器收到 HTML 并渲染
某个电商网站采用 SSR 来解决 SPA 的问题。但他们的页面上有个"推荐商品"接口,需要调用机器学习模型,耗时较长。
反而,SSR 让首屏变得更慢了。
需要服务器
你得部署一台 Node.js 服务器来做这个事情。流量一上来,很容易就挂了。
一个创业公司采用 SSR,但容量规划不足。在流量高峰期,服务器崩溃,整个网站无法访问。
开发复杂
你写的代码得同时考虑在浏览器和服务器两种环境下运行。比如:
-
在服务器上不能访问
window对象 -
在服务器上不能访问 DOM
-
要避免内存泄漏
-
要考虑代码的兼容性
这种心智负担很重。
许多开发者在 SSR 时踩过坑。比如在组件里直接访问 window.location,结果在服务器上报错。
服务器负载高
当请求量很大时,服务端负载会比较高。每次请求,服务端同构代码都会执行一遍,这对服务器的稳定性和容灾设计是一种考验。
SSR 的适用场景
优势:
-
页面性能较好:在服务端数据获取快的情况下,首屏性能较好。
-
容灾完备:在服务端出现故障后,通常可以降级到 CSR 渲染模式。
-
统一的心智模型:不需要了解额外的后端模板技术。
-
SEO 友好。
不足:
-
页面性能可能较差:如果获取动态数据耗时比较高,会导致 TTFB 耗时较高,从而导致白屏时间较长。
-
需要额外部署和维护 Node.js 服务器,增加了运营资源成本。
-
写代码时需要考虑代码在服务端的兼容和内存泄漏的规避,对开发人员的技术有一定要求。
-
由于每次请求服务端同构代码都会执行一遍,当请求量很大时,服务端负载会比较高。
流式渲染
问题的出现
SSR 还是不够快。关键瓶颈在于:SSR 首屏时间受限于最慢的后端接口。
如果你的页面有 10 个接口,其中 9 个 100ms 就返回了,但有 1 个需要 1 秒钟,那么整个页面就要等 1 秒钟才能渲染。
这太浪费了。
流式渲染的思想
流式渲染的想法很简单:为啥要等所有菜都做好了再上?先上个凉菜不行吗?
核心思想是:
-
先发送 head:让浏览器尽早开始下载 CSS、JavaScript。
-
分块发送 body:哪个数据接口先回来,就先把那部分内容发过来。
-
骨架屏占位:慢的接口部分,先用骨架屏顶着。
-
动态替换:当慢的接口返回后,通过 JavaScript 脚本替换骨架屏。
流式渲染的优势
-
页面性能极好:不用等所有接口都返回,用户能更快地看到内容。
-
渐进式加载:用户体验好,页面逐步加载,不会一直白屏。
流式渲染的问题
-
DX 体验不足:开发的心智成本高,需要对页面进行划分,并且可能需要后端配合。比如有的页面可能只有一个后端接口,需要拆分。
-
复杂度高:需要处理骨架屏、动态替换等逻辑。
有趣的是
流式渲染实际上是传统 MPA 的早期性能优化方案。这里只是历史的螺旋上升。
几十年前,网站就是这样做的:先发送 HTML 的一部分,然后继续发送剩余的部分。
现在我们又回到了这个思想,只是加上了现代的框架和工具。
就像一个圆圈,我们走了一圈,又回到了起点。但这一次,我们带回了新的知识和工具。
淘宝、eBay、Amazon 的内部框架都采用了流式渲染。
这些大公司的实践证明,流式渲染确实能带来显著的性能提升。
混合模式
最佳实践
像 Next.js、Remix 这样的框架采取了一个聪明的策略:
首次 SSR,后续 SPA。
这样可以结合两者的优点:
-
首屏快(SSR)
-
后续导航流畅(SPA)
前沿探索:服务器组件
问题的出现
即使是混合模式,还是有一个问题:客户端的 JavaScript 体积太大了。
一个现代的 SPA,光是框架代码就有几百 KB。如果用户的网络不好,下载这些 JavaScript 就要花很长时间。
服务器组件 (RSC)
React 团队提出了一个激进的想法:为什么所有东西都要发送到客户端?
一个页面上,不是所有东西都需要交互。比如:
-
文章内容:静态的,不需要交互
-
页头页脚:静态的,不需要交互
-
评论列表:可能需要分页,但不需要复杂的交互
这些部分完全可以在服务器上渲染好,直接发送 HTML。
页面 =
服务器组件(文章内容、页头页脚)+
客户端组件(评论框、点赞按钮)
只为那些需要交互的"岛屿"发送 JavaScript。
优点
-
减小打包到客户端 JS 的 bundle size:不需要发送所有的代码,只发送那些需要交互的部分。
-
更好的性能:客户端的 JavaScript 更少,加载更快。
缺点
-
心智复杂:你需要区分哪些组件是服务器组件,哪些是客户端组件。
-
Bug 多,漏洞多:这是一个相对较新的技术,不够成熟稳定。React 服务器组件在 2025 年还发现了安全漏洞。
-
不支持 CSR 降级容灾:如果服务器出问题,没有备选方案。
适用场景
-
轻交互的、重展示的站点
-
静态文档生成
-
内容网站
竞品
如果你觉得 React 服务器组件太复杂,可以考虑 Astro,它提供了类似的功能但更简洁。
结论
回顾整个历史,你会发现没有完美的技术,只有最适合场景的技术。
从 MPA 的简单直接,到 SPA 的丰富交互。从 SSR 的"两全其美",到流式渲染和服务器组件的极致优化。
每一次演进,都是在解决上一代技术留下的问题,然后又带来新的问题。
这就是历史的螺旋上升。