第 8 章 请求的第一站:浏览器与前端基础
副题:白屏之谜——浏览器拿到网页之后,到底发生了什么
第二部分我们画完了四张图纸:需求清单、技术选型、数据模型、接口。现在,图纸上的系统要真正跑起来了。从这一章开始,视角切换:跟着一次真实的请求,看它在系统里怎么走。第一站,是请求的起点和终点都在的地方:浏览器。这一站回答一个问题——页面到底是怎么被画出来的?为什么有时候画不出来(白屏)?
本章要建立的认知
- 网页是三层分工的产物:HTML(结构)、CSS(表现)、JavaScript(行为)——分工出自"内容与表现分离"的工程决策;
- 浏览器拿到 HTML 后要走一条渲染管线:解析 → 合成渲染树 → 布局 → 绘制——每一步都可能成为白屏的原因;
- 首屏快慢由关键渲染路径决定:CSS 阻塞渲染、JS 阻塞解析——"页面慢"的第一站答案在这里,完整优化在第 16 章。
8.1 白屏之谜
故事从阶段 1 的"开发中"开始。上一章接口清单定稿,前端对着契约开工,你也开始搭页面。老周等了三周,终于等来一个能打开看的版本——结果页面打不开。
"什么现象?"你问。
"就白屏,一片空白。"
"转圈了吗?"
"没有。"
"报错了吗?"
"也没有,就是白。"
"打不开"其实有三种完全不同的形态,每种指向系统里不同的环节:
- 转圈:浏览器一直在等服务器响应——网络或服务端没回来(看第 10、11、23 章)。
- 报错:请求有响应但内容不对——接口契约对不上,或者服务器抛了 5xx(看第 7 章)。
- 白屏:浏览器已经拿到了响应,但页面没画出来——问题不在网络,不在服务器,在浏览器拿到 HTML 之后、画到屏幕之前。
三种形态,排查入口完全不同。转圈看 Network 面板里挂着的 pending 请求;报错看 Console(JS 报错)和 Network(4xx/5xx);白屏看 Elements(HTML 有没有变成 DOM)和 Performance(管线走到哪)。
"打不开"先分形态,再找入口——这一步做对了,排查就完成了一半。
在往下走之前,先确认一个细节:老周说的"白",到底是真白屏,还是"画了但内容区是白的"?
真白屏是浏览器什么都没渲染;后者是 CSS 没生效、或者内容没填进去。怎么区分?F12 打开 Network,看 HTML 请求有没有成功返回;再看 Elements,HTML 有没有被解析成 DOM 节点。
排查的第一步永远是确认问题在哪一层。 这个习惯,后面每一章排障都会用到。
老周属于真白屏:请求到了服务器,服务器也返回了 HTML,但屏幕一片空白。
这就引出一个平时没人想的问题:浏览器拿到 HTML 之后,到底做了什么?
你可能每天打开几十个网页,但几乎从没想过"页面是怎么来的"。这不是疏忽——浏览器把整个过程藏得太好了,用户只看到结果。但"藏得好"恰恰是麻烦:结果不对时,你不知道中间哪一步断了,只能瞎猜。
白屏之所以难排查,就是因为它发生在"黑箱"里。 网络通了,服务器回了,但浏览器内部那条从 HTML 到像素的管线,卡在了某个你看不见的环节。
要定位老周的白屏,必须先把这条管线拆开看。"渲染"这个词背后,其实是解析 → 合成 → 布局 → 绘制的完整链条,每一段都可能卡住,每一段都有对应的排查方法。
这一章就沿着这条管线走一遍:先看网页的三层分工(HTML、CSS、JS 为什么长这样),再走渲染管线的每一步,最后用关键渲染路径回答——老周的白屏到底卡在哪、怎么定位、怎么修。
从点击到显示,一次请求要穿过四层:浏览器、网络、服务端、数据层。本章聚焦第一层——浏览器里发生了什么。网络段(DNS、CDN、HTTP)留到第 10、11 章;服务端和数据层在第 12-14 章。现在,先看旅程的起点。
这张图和第 1 章那张技术地图读法一样:先抓主轴(一条请求的路径),再沿路径看每一站。往后每读一章,你都可以在图 8-1 上找到自己的位置——第 10 章放大网络,第 12 章放大服务端,第 15 章把整条线串起来。你读到的始终是同一张地图,只是不断放大。
8.2 网页的三层分工
老周看到的内容流页面,本质上由三样东西拼成。这是 Web 的基石,任何网页——包括你正在读的这个页面——都离不开它们:
- HTML:结构。页面上有什么。标题、段落、图片、按钮。老周看到的内容列表,在 HTML 里是一组
<article>标签。 - CSS:表现。这些东西长什么样。字体、颜色、间距、圆角。内容流的卡片样式、橙色按钮,都在 CSS 里。
- JavaScript:行为。页面怎么响应。点击、滚动、加载更多。内容流"下拉刷新"的逻辑,是 JS 在跑。
为什么要拆成三层?这是一个工程判断:内容与表现分离。三个问题——"有什么""长什么样""怎么动"——的变化频率完全不同。内容天天改(老周发新帖),样式偶尔改(改版),行为按版本改(加新交互)。变化频率不同的东西,分开维护才改得起。 这和第 6 章判断实体边界的逻辑一模一样:独立生命周期、独立业务规则,就该独立成层。
这个分工也不是一天长出来的。早期 Web 只有 HTML,页面是静态文档,样式全靠浏览器默认。后来网页变动态了,内容由程序生成,但样式还混在 HTML 里——<font> 标签、bgcolor 属性写得到处都是。改一次全站配色要翻几百个文件,维护噩梦由此开始。1996 年 CSS 发布,样式终于从内容里剥离;1995 年 JavaScript 诞生(最初叫 LiveScript,十天设计出来的语言),交互有了落脚处。三层分工,是二十年演进沉淀下来的稳定形态。理解了这段历史,就理解了"为什么偏偏是这三层":每一层都是被上一层的痛点逼出来的。
<!-- 结构:内容流的一条卡片 -->
<article class="post">
<h2 class="post-title">一台二手相机</h2>
<p class="post-body">九成新,快门数两万……</p>
<span class="post-author">@laozhou</span>
</article>
/* 表现:卡片长什么样 */
.post { border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; }
.post-title { font-size: 18px; color: #333; }
// 行为:点击卡片做什么
import { fetchContents } from './api.js'; // 第 7 章的接口封装
document.querySelectorAll('.post').forEach(card => {
card.addEventListener('click', () => openPost(card));
});
今天的 JS 早已不是 1995 年那个"十天的语言"。ES6+ 带来了模块化、类、async/await,配合构建工具(第 21 章),现代前端代码的组织方式和后端工程没什么两样。但有一点没变:JS 独占浏览器的主线程。它既是前端的王牌,也是前端的负担——跑太久,页面就卡住。
JS 能"边等边干"而不卡死,靠的是事件循环。主线程把耗时的等待(网络请求、定时器)交给浏览器底层,自己继续跑别的;事情完成后,回调被塞回队列,等当前任务结束再执行。理解事件循环,就理解了为什么 setTimeout 不准时(回调要排队)、为什么 async/await "不阻塞"(只是把后续代码变成回调)、以及为什么第 16 章要把大计算拆小——主线程一次跑太久,事件循环就转不动,用户就会感觉页面"卡了"。
三层分工还有一个容易被忽略的收益:语义化。
<article>、<h2>、<p> 除了给 CSS 挂样式,还告诉浏览器、搜索引擎、读屏器"这是什么"。用 <div> 包一切是反模式,因为 <div> 只表示"这里有个盒子",不表示"这是一篇帖子"。写 HTML 时先问"这个内容是什么",再选标签,比"先 div 再说"多花三秒钟,省的是机器理解你页面的一整天。
常用语义标签混个脸熟:<header>(页头)、<nav>(导航)、<main>(主内容)、<article>(独立内容块)、<section>(分区)、<footer>(页脚)、<aside>(侧栏)。一个语义化的页面骨架,就是这些标签的合理嵌套。
再说 CSS 的 Cascading(层叠)。同一个元素可能被多条规则命中:浏览器默认、页面样式、内联样式。最终生效谁,由"优先级 + 来源 + 顺序"层层叠加决定。内联样式 > id 选择器 > 类选择器 > 标签选择器 > 浏览器默认。理解层叠,才能解释前端最常见的困惑——"我明明写了样式,为什么没生效?" 大概率代码没错,是被层叠规则压下去了。
分工解决了"改得起",但代价是协同。HTML 结构改了,CSS 选择器可能失效;JS 改了 DOM,样式可能对不上。改一层要想着另外两层,这个协同问题正是第 9 章前端框架要解决的。
到了 SPA(单页应用)时代,分工的边界发生了挪动。传统网页里,HTML 是主体,JS 是点缀;SPA 里,服务器返回的 HTML 往往只剩一个空壳(一个根节点),页面结构本身由 JS 生成。第 5 章选的 React 就是这条路——"三层分工"变成了"HTML 是空壳、CSS 管样式、JS 管结构 + 行为"。
边界挪了,但判断没变:内容仍然和表现分离,只是"结构"这一层从 HTML 挪进了 JS。这是第 9 章"声明式 UI"的前奏——组件化的雏形,就是"结构 + 行为绑定在一起"。
对后端读者特别重要的一点:页面是谁画的,有两种完全不同的模式。
传统服务端渲染(SSR):服务器用模板把数据填进 HTML,返回完整页面。浏览器拿到就能直接画。第 12 章会讲模板引擎。
单页应用(SPA):服务器返回一个空壳 HTML(根节点 + JS 引用)。浏览器先下载 JS,JS 再调接口(第 7 章的契约)拿数据,然后动态把内容填进页面。案例选的是 React,也就是 SPA——内容流的卡片由浏览器里的 JS 调 GET /v1/contents 拿到数据后创建,不是服务器画好的。
这个区别直接决定白屏的根因:
- SSR 的白屏:服务器没响应或响应慢,浏览器干等着。
- SPA 的白屏:服务器 HTML 到了,但"下载 JS → 执行 JS → 调接口 → 填内容"这条链条上某个环节断了。
老周的白屏属于哪一种?如果是 SPA,排查入口就不是 Network 里 HTML 有没有回,而是 Console 里 JS 有没有报错、JS 包有没有下载成功。
选 SSR 还是 SPA,兑现的是第 5 章的选型决策。案例选 SPA 的理由:前后端同语言(React + Node),阶段 1 没有 SEO 压力。这些理由写在第 5 章的决策记录里,现在你可以看到它们如何影响具体的技术表现。
SPA 还有一类特有的白屏要认识:空壳白屏。服务器返回的 HTML 是个空壳,内容全靠 JS 填。如果 JS 包下载失败、执行报错,页面就会"HTML 到了,但永远白着"。这类白屏的排查入口是 Console 面板的报错,不用去查 CSS——两种白屏,两条路径,后面会区分清楚。
最后提一句工程现实:浏览器下载的那个 JS,是构建工具(第 21 章)把成百上千个源文件打包后的产物,不是手写的单文件。包有多大、怎么拆分、怎么缓存,都是第 16 章和第 21 章的话题。浏览器看到的永远是"一个 HTML + 几个 JS/CSS 文件",这一层工程化的复杂度,构建工具在文件到达浏览器之前就处理掉了。
现在,三层的分工清楚了。接下来要看的是:浏览器拿到这三层之后,具体怎么把它们变成屏幕上的像素?老周的白屏,卡在这条管线的哪一段?
8.3 渲染管线:从 HTML 到像素
回到老周的白屏。浏览器拿到 HTML、CSS、JS 之后,要沿着一条固定的管线一步步走,才能画到屏幕上。这条管线有五步,老周的白屏,就卡在其中某一步上。
第一步:解析。
浏览器先读 HTML,像拼积木一样,把标签搭成一棵 DOM 树——<article> 变成节点,里面嵌套的 <h2> 变成子节点,父子关系就是树的层级。同时,浏览器也在读 CSS,搭出另一棵叫 CSSOM 的树。这时候两棵树是独立的,还没碰面。
HTML 解析器有个特点:特别宽容。写错了标签、忘了闭合,它不会报错,而是尽量猜着修。这来自早期互联网的兼容性要求——1990 年代的网页什么烂代码都有,浏览器要是严格报错,半个互联网都打不开。好处是容错能力强,坏处是"HTML 写错了也不报错"成了常态,所以工程上需要 lint 工具来兜底(第 20 章会讲)。
第二步:合成渲染树。
浏览器把 DOM 树和 CSSOM 树合到一起,生成渲染树(Render Tree)。这是"页面最终长什么样"的蓝图,但有两个过滤规则:
display: none的元素直接扔掉,不进渲染树——不占空间,就当它不存在。visibility: hidden的元素会进渲染树——占着空间,只是看不见。
两者的区别解释了前端一个常见困惑:为什么 display: none 的元素量不到尺寸?因为它根本不在渲染树里,浏览器没给它算位置。为什么切显示状态时用 display 会"闪一下"而 visibility 不会?因为前者要重建渲染树、重新布局,后者只是变透明。
还有一个细节:伪元素 ::before、::after 在 DOM 里不存在,但在渲染树里有位置和样式。所以 JS 不能直接操作伪元素——它连 DOM 都没进。
第三步:布局。
渲染树有了,浏览器开始计算每个元素在页面上的具体位置和大小:卡片放顶部、标题放左上角、图片占 200×150 像素。这一步也叫回流(reflow)。窗口缩放、内容插入、样式变化,只要元素的位置或尺寸变了,布局就要重算。
布局的基本单位是盒模型。每个元素都是一个盒子,从内到外四层:content(内容)→ padding(内边距)→ border(边框)→ margin(外边距)。
这里有个新手必踩的坑:box-sizing。默认的 content-box 下,width: 200px 只算内容宽度,加上 padding 和 border 后实际会更宽。而 border-box 下,width: 200px 就是盒子总宽。前端实践几乎统一全局设置 border-box,因为"说多宽就多宽"更直观,不用心算 padding。
第四步:绘制。
位置算好了,浏览器开始把每个盒子真正画成像素:铺背景、描边框、写字、贴图。只要元素的颜色、背景这些视觉属性变了,就要重新画,这叫重绘(repaint)。
绘制是有先后顺序的,由层叠上下文决定。z-index 能工作,靠的就是这个机制。但注意:z-index 只在同一个层叠上下文里比大小,跨上下文时"调了没用"。很多前端困惑的"z-index 不生效",根子在这里。
第五步:合成。
现代浏览器不会一次性画完整张页面,而是把它切成若干图层,各层分别画好,最后叠在一起输出到屏幕。滚动页面时,只有滚动的那个图层在移动,不用把整页重画一遍;transform 和 opacity 动画也只动图层位置,不走布局、不重新绘制——这是动画能 60 帧流畅运行的秘密,第 16 章性能优化会反复用到。
五步串起来记:先解析成树,再合成渲染树,然后算位置,接着画出来,最后叠上去。
各段的成本不是一个量级。解析最便宜(处理字符,毫秒级),布局较贵(几何计算,影响全局),绘制更贵(像素填充,面积越大越贵),合成最便宜(只搬图层)。所以前端性能优化的经验法则就是:能走合成就不绘制,能走绘制就不布局——让管线走得越短越好。
还有一个关键事实:以上所有步骤,和 JS 执行,都在浏览器的同一个主线程上排队。
JS 在跑的时候,解析、布局、绘制全得等着。这就是为什么 JS 阻塞渲染——一个死循环能让整个页面冻住。第 16 章讲长任务优化,核心就是"把大计算拆小,让出主线程",让事件循环有机会去画画页面。
最后和第 9 章接个头:渲染树是浏览器层面的"物理树",描述"最终画什么";第 9 章的组件树是开发者层面的"逻辑树",描述"业务怎么组织"。框架的职责之一,就是把你的组件树翻译成浏览器的 DOM 树,再变成渲染树。两棵树的组织方式不同——你按"帖子卡片"来思考,浏览器按"几百个盒子和文本节点"来排布——这个差距,就是框架帮你填平的地方。
现在管线的五步清楚了。老周的白屏到底卡在哪一步?
8.4 关键渲染路径:白屏的答案
管线走完了,但白屏说明浏览器在画出第一个像素之前,某一步卡住了。
答案在关键渲染路径(Critical Rendering Path):从收到 HTML 到屏幕出现第一个像素,浏览器必须走完的最短管线。这条路径上有两个最常见的卡点,都出在资源阻塞上。
第一,CSS 是渲染阻塞资源。
合成渲染树(8.3 第二步)需要 CSSOM,所以浏览器必须等 CSS 全部下载并解析完,才开始画页面。CSS 没到,页面就白着——不是"样式不好看",而是"什么都没有"。这就是为什么 CSS 文件要放在 <head> 里、体积要尽量小:它在关键路径上,晚一秒到,白屏就多一秒。
例外:带媒体查询的 CSS 不阻塞。比如 <link rel="stylesheet" media="print"> 只服务于打印,浏览器不会等它。非关键资源,不进关键路径。
第二,JS 是解析阻塞资源。
浏览器解析 HTML 是逐段进行的,遇到 <script> 就会停下来,先下载并执行完这段 JS,再继续解析后面的 HTML。为什么?因为 JS 可能修改 DOM(document.write、创建节点),浏览器不敢赌它会不会改后面的结构,只能等。所以 <script> 要放在 </body> 前,或者加 defer/async——它在关键路径上,放在文档中间会让后续 HTML 全部排队。
把这两个卡点串起来,关键路径的时序大致是:
收到 HTML
→ 开始解析
→ 遇到 CSS 链接 → 暂停,下载并解析 CSS(阻塞)
→ 遇到 JS 标签 → 暂停,下载并执行 JS(阻塞)
→ 解析完成,DOM 就绪
→ DOM + CSSOM 合成渲染树
→ 布局
→ 绘制 → 第一个像素出现
白屏的时间,就是这条路径的长度。
怎么定位卡点?
打开 Performance 面板,录制一次页面加载。时间线上你能清楚看到:HTML 解析段、样式计算段、布局段、绘制段——每一段多长、卡在哪,一目了然。关键路径不抽象,就是面板里一段可见的时间线。
配合 Network 面板一起看:HTML 到了吗?到了。CSS 到了吗?如果某个 CSS 请求一直 pending,或者文件巨大,白屏就是在等样式。JS 呢?如果某个脚本执行报错,初始化逻辑中断,DOM 可能根本没建起来——这也是一种白屏。
排查口诀:沿着"HTML → CSS → JS → 渲染树 → 布局 → 绘制"一路问,卡在哪一步,答案就在哪一步。
两个解药先认识一下:
defer和async:给<script>加的属性。defer表示"下载不阻塞解析,等 HTML 全部解析完再按顺序执行";async表示"下载完立刻执行,不等解析也不保证顺序"。defer 保顺序,async 保速度,选哪个取决于脚本有没有依赖关系。细节第 16 章展开,现在记住"JS 默认阻塞,defer/async 是解药"就行。preload和preconnect:preload告诉浏览器"这个资源马上要用,提前下载";preconnect提前和关键服务器建立连接,省掉 DNS 和 TCP 握手时间。两者都是在浏览器自己发现资源之前插手调度——优化关键路径的本质,就是让浏览器"更早知道、更早动手"。
老周的白屏是怎么解决的?
排查步骤:Network 面板确认 HTML 已返回 → 发现 CSS 请求挂着,一个 2MB 的样式文件(写页面时把整个 UI 库的 CSS 全引进了)→ 把 CSS 拆成关键样式(直接内联到 HTML)和非关键样式(按需加载)→ 白屏从 3 秒降到 0.5 秒。
老周说"好多了"。这就是关键路径认知的完整变现:知道 CSS 在关键路径上,才知道该往哪儿查、往哪儿改。 这也呼应了第 4 章的验收标准——"首页 3 秒首屏"落到浏览器里,就是"关键路径 < 3 秒"。需求清单的每一行,都要在运行时找到对应的实现机制。
纠正一个常见混淆:"页面慢"和"白屏"是两回事。
白屏是"第一个像素出现之前"的时间,由关键路径决定。像素出现之后,图片加载、JS 初始化、交互响应慢,那是另一回事,第 16 章再讲。本章只回答一个问题:第一个像素,什么时候出现?
这次报障放到更大的画面里看,又是第 2 章演进循环的实例:
业务正常推进(复杂度积累:一个 2MB 的 CSS)→ 白屏暴露(旧方案撑不住了)→ 引入新技术(关键路径优化)→ 解决(白屏 0.5 秒)→ 新代价(样式拆分后要管理加载时机,第 16 章继续演进)。技术是被事故逼出来的。
第 16 章会展开三个优化方向,这里先预告:
- 压缩:资源变小,路径变短
- 内联:关键 CSS 直接嵌进 HTML,省一次请求
- 拆分:首屏只要关键资源,其余按需加载
三个方向都指向同一件事:缩短关键路径。
8.5 渲染的代价与边界
管线和关键路径讲完了,这一章的边界需要说清楚。
本章只负责建立认知,不动手优化。 你知道了浏览器里有"解析 → 渲染树 → 布局 → 绘制 → 合成"这条管线,知道了 CSS 和 JS 会在关键路径上阻塞渲染,这已足够。真正动手做优化——减少回流、拆分关键资源、懒加载、缓存策略——那是第 16 章性能优化的系统工程。一句话分清边界:第 8 章回答"页面是怎么画出来的",第 16 章回答"怎么画得更快"。 没有前者的机制,后者的手段只是死记硬背;有了前者的机制,所有优化手段都能自己推导。
浏览器有差异,但管线是共识。 Chrome、Safari、Firefox 的渲染引擎各不相同,实现细节也有差别,但五步管线的形状是所有现代浏览器的共同语言。理解这条通用框架,你就拿到了跨浏览器排查问题的地图;具体引擎的差异,遇到时再查文档即可。
DOM 操作是昂贵的。 JS 每修改一次 DOM,浏览器都可能重新计算布局(reflow)和重绘(repaint)。而 reflow 的代价往往是全局的——一个元素尺寸变了,它的兄弟、父级甚至整页都可能要跟着重算。当交互变复杂、DOM 操作变频繁时,手动操作 DOM 会成为性能和维护的双重负担。这正是下一章前端框架要解决的核心问题。
渲染管线背后的**"管道思维"**还有迁移价值。输入 → 解析 → 合成 → 输出,这种管道模型在后端(请求 → 中间件 → 业务 → 响应)、数据层(查询 → 计划 → 执行)、CI(提交 → 构建 → 测试 → 发布)里随处可见。第 8 章教的"定位卡点",放在前端之外照样适用:先确认管线走完了没有,再确认每一步的结果对不对。
管线的每一段都可能出岔子。 JS 报错导致初始化中断,DOM 只建了一半,出现"半白屏";图片加载失败,绘制时留下裂图;CSS 文件损坏,样式全丢变成"裸页面"。排查的经验法则是:先做流程检查(关键路径上的资源到没到),再做结果检查(Elements 和 Network 面板里,每一步的产物是否正常)。
最后预告两个第 16 章要用的指标:FCP(First Contentful Paint,第一个内容出现的时间)标记白屏结束,LCP(Largest Contentful Paint,最大内容出现的时间)标记主要内容就绪。老周的白屏,本质上就是 FCP 太久。
8.6 本章对应表
| 业务诉求 | 技术选择 | 为什么 | 代价/取舍 |
|---|---|---|---|
| 页面上有什么 | HTML(结构) | 语义化内容,机器可读(搜索引擎/读屏器) | 纯结构没有样式,要 CSS 配合 |
| 页面长什么样 | CSS(表现) | 内容与表现分离,变化频率不同分开维护 | 选择器与结构耦合,改结构要同步改样式 |
| 页面怎么响应 | JavaScript(行为) | 交互逻辑与内容分离 | 默认阻塞解析,加载时机要管理 |
| 页面不能白屏太久 | 关键渲染路径优化 | 白屏=关键路径长度,CSS 阻塞渲染/JS 阻塞解析 | 优化是系统工程(第 16 章深化) |
| 白屏了怎么排查 | 渲染管线理解 | 沿着管线问"到哪一步了",卡点即答案 | 浏览器引擎有实现差异 |
本章从老周的白屏出发,走完了浏览器的完整旅程:三层分工(8.2)、渲染管线(8.3)、关键路径(8.4)与优化边界(8.5)。在旅程图(图 8-1)上,浏览器既是用户输入网址的起点,也是响应渲染成页面的终点——第 8 章是唯一"起点与终点同站"的一章。理解浏览器,就等于同时握住了旅程的出发和到达。
本章小结
-
网页是三层分工的产物:HTML 结构、CSS 表现、JS 行为——分工的依据是变化频率不同,分开维护才改得起;语义化让内容机器可读;
-
渲染管线五步:解析(DOM/CSSOM)→ 合成渲染树 → 布局 → 绘制 → 合成——每一步都有专业名词(reflow/repaint),是理解前端性能问题的地基;
-
关键渲染路径回答白屏:CSS 阻塞渲染、JS 阻塞解析——白屏时间 = 关键路径长度,排查沿着管线问"到哪一步了";
-
"页面慢"和"白屏"是两回事:本章只回答第一个像素之前的事,完整优化在第 16 章;
-
DOM 操作昂贵——这是第 9 章要解决的问题:交互复杂之后,手动操作 DOM 撑不住。
下一章
老周的白屏解决了——CSS 没到,等 CSS。页面能打开了,内容流也渲染出来了。
但下一个问题马上就来:内容流要加载更多、评论要展开收起、下单流程要分步交互——页面的交互越来越复杂,代码里到处是"找到这个节点、改它的样式、再找那个节点、换它的内容"。改着改着,你发现:手动操作 DOM 的代码,越来越难维护了——插卡片、改样式、同步状态,每一处都要记得"先找到节点"。
下一章,前端框架:为什么需要声明式 UI——页面复杂度上来之后,直接操作 DOM 为什么撑不住,以及框架是怎么解决这个问题的。