DAY 2
1. 从输入 URL 到页面渲染完成的完整流程是什么?每一步的核心工作?
整个流程核心分为网络请求和页面渲染两大阶段:
- 网络阶段:先做 URL 合法性校验和本地缓存检查,缓存未命中就通过 DNS 解析拿到服务器 IP,和服务器建立 TCP 连接(HTTPS 会额外做 TLS 加密协商),随后发送 HTTP 请求拿到 HTML 核心资源,完成数据传输。
- 渲染阶段:拿到 HTML 后解析生成 DOM 树,同时解析 CSS 生成 CSSOM 树,两者合并成只包含可见节点的渲染树;接着通过布局计算节点的位置和尺寸,再完成图层绘制,最终把所有图层合成输出到屏幕,完成页面渲染。
2. 浏览器的渲染流程是什么?DOM 树、CSSOM 树、渲染树的关系?
DOM 树管结构,CSSOM 树管样式,渲染树是二者结合后的 “可见版精简合体”,是浏览器最终布局、绘制页面的唯一依据。
-
依赖关系渲染树必须依赖 DOM 树 + CSSOM 树才能生成,缺一不可;DOM 与 CSSOM 解析可并行,但生成渲染树需要两者都解析完成。
-
包含关系渲染树是DOM 树的子集(只留可见节点)+ CSSOM 树的映射(样式匹配到对应节点)。
-
关键细节
visibility: hidden节点:在渲染树中,仅不可见,会参与布局;display: none节点:不在渲染树中,不参与布局与绘制;- 渲染树只负责 “长什么样、在哪”,布局和绘制完全基于它执行。
3. 什么是重排 / 重绘?哪些操作会触发重排 / 重绘?如何避免?
-
重排(Reflow) :元素几何尺寸 / 位置变化,浏览器重新计算布局 → 开销大
-
重绘(Repaint) :只改颜色、背景等不影响布局 → 开销小
-
触发重排一定会触发重绘,反之不一定
触发条件: 字体、内容长度、窗口大小改变等。
原始的解决思路是先读后写、批量修改DOM、动画优先采用opacity、tranform等; 但React等现代前端框架已经帮我们解决了许多上述问题,在React中,可通过以下手段避免重绘、重排:
- 避免组件不必要的渲染,使用useMemo、React.memo、useCallback避免多余的渲染;
- 长列表:注意添加key做唯一标识,同时可使用VirtualList等组件只渲染视口内的内容。
4. 什么是 HTTP 缓存?分为哪两类?核心区别是什么?
浏览器对之前请求过的静态资源(JS/CSS/ 图片 / 接口) ,在本地做一份副本存储,下次再请求时优先使用本地副本,以此减少网络请求、加快页面加载、降低服务器压力,这个机制就是 HTTP 缓存。
核心区别: 是否需要向服务器发送 HTTP 请求进行校验。
强缓存
不发任何请求浏览器直接从本地拿缓存,连一个请求包都不会发给服务器。Network 里直接显示:200 (from memory cache)。
协商缓存
必须发一次正常的 HTTP 请求 不是什么 “单独的校验请求”,就是你原本要请求的那个资源请求,只是请求头里带上了:
If-Modified-Since- 或
If-None-Match
5. 强缓存的响应头有哪些?过期了会怎么样?
强缓存对应的响应头
控制强缓存的响应头就两个:
- **
Cache-Control: max-age=秒数**HTTP/1.1 标准,相对时间,现代项目主流使用 - **
Expires: 绝对时间字符串**HTTP/1.0 旧标准,受本地时间误差影响,优先级低于 max-age
只要其中一个生效且在有效期内,就命中强缓存。
强缓存过期了会怎么样
-
不再直接使用本地缓存浏览器不会再直接读 memory/disk cache,而是必须发起一次真实的 HTTP 请求。
-
**自动降级走「协商缓存」**请求头会自动带上:
If-Modified-Since: 上次的 Last-ModifiedIf-None-Match: 上次的 ETag
-
服务端校验结果:
- 资源没变化 → 返回 304 Not Modified→ 浏览器继续用本地旧缓存
- 资源已更新 → 返回 200 + 新内容→ 浏览器用新内容,并更新本地缓存
6. 协商缓存的响应头有哪些?Etag 和 Last-Modified 的区别?
协商缓存是一问一答的机制:
- 服务器下发:响应头
- 浏览器下次请求带上:请求头
服务端响应头(第一次返回)
Last-ModifiedETag
浏览器请求头(第二次发请求)
If-Modified-Since→ 对应Last-ModifiedIf-None-Match→ 对应ETag
7. 为什么需要协商缓存?强缓存不能解决所有问题吗?
强缓存只管快,不管新。协商缓存解决的是:我想缓存,但我又想在资源更新时能拿到最新的。
带 hash 的静态资源,靠文件名区分版本,所以可以永久强缓存;HTML 文件名不能变,所以必须用协商缓存保证最新。
8. 什么是跨域?浏览器为什么有同源策略?
浏览器规定,协议、域名、端口三者完全一致,才叫「同源」,只要有任意一个不一样,就是跨域。
只要有任意一个不一样,就是跨域。
同源策略是浏览器的安全底线,专门防止恶意网站跨站偷 Cookie、偷数据、伪造请求搞破坏。
跨域是浏览器的限制,服务器之间通信没有跨域一说。
9. 前端跨域的解决方案有哪些?分别适用于什么场景?
-
CORS后端配置响应头允许跨域,前端无需改动。适用:前后端分离项目、生产环境接口跨域,标准通用方案。
-
开发环境代理(webpack / Vite proxy) 本地启动 Node 代理转发请求,避开浏览器跨域限制。适用:本地开发调试,不影响线上。
-
Nginx 反向代理用 Nginx 统一域名,内部转发接口。适用:项目线上部署,解决生产跨域。
10. HTTP/1.1、HTTP/2 的核心区别是什么?
-
多路复用 HTTP/1.1 同一域名最多同时开 6~8 个 TCP 连接,请求多了会排队阻塞;HTTP/2 用二进制分帧 + 单连接多路复用,多个请求共享一个 TCP 连接,互不阻塞。
-
头部压缩(HPACK) HTTP/1.1 每次请求都携带完整、重复的 Header;HTTP/2 对头部做压缩,大幅减少体积。
-
二进制协议 HTTP/1.1 是纯文本协议,可读性好但效率低;HTTP/2 是二进制分帧协议,解析更快、更紧凑、更安全。
-
服务端推送(Server Push) HTTP/2 支持服务端主动把 CSS、JS 推给浏览器,不用等 HTML 解析后再请求;HTTP/1.1 只能浏览器主动请求。
-
队头阻塞问题HTTP/1.1 存在严重队头阻塞(一个请求卡住,后面全堵);HTTP/2 在单连接上通过多路复用基本解决了应用层队头阻塞。
HTTP/2 核心就是更快、更省连接、头部更小、支持服务端推送,解决了 HTTP/1.1 的队头阻塞和性能瓶颈。
11. HTTP/2 的多路复用原理是什么?解决了什么问题?
HTTP/2 多路复用原理
- 基于二进制分帧:将请求和响应数据拆分成更小的二进制帧,每个帧都带有所属流(Stream)的唯一标识。
- 单 TCP 连接复用:同一个域名下,所有请求共享一条 TCP 连接。
- 帧乱序传输:多个请求的帧可以交错、并行传输,接收端根据帧的标识重新组装成完整数据,互不干扰。
解决了什么核心问题
-
HTTP/1.1 的队头阻塞HTTP/1.1 一个连接同一时间只能处理一个请求,前一个请求阻塞会导致后续请求全部排队;多路复用让请求真正并行,不再排队。
-
TCP 连接过多的开销HTTP/1.1 需开 6~8 个 TCP 连接并行请求,握手慢、耗资源、带宽竞争;HTTP/2 单连接即可,大幅降低开销。
-
告别繁琐性能优化不再需要精灵图、资源合并、域名分片等手段来规避连接限制。
12. HTTPS 的核心作用是什么?加密原理是什么?
核心就三件事:防窃听、防篡改、防冒充。
HTTPS 用非对称加密安全交换对称密钥,再用对称加密高效传输数据,配合证书保证身份可信,实现安全通信。
三次握手建连接,四次挥手断连接。
13. TLS 握手的核心流程是什么?
- Client Hello客户端发送:支持的 TLS 版本、加密套件列表、客户端随机数。
- Server Hello服务端选定:TLS 版本、加密套件,返回服务端随机数 + 数字证书(内含公钥)。
- 客户端验证证书验证证书是否由可信 CA 颁发、是否过期、域名是否匹配,防止伪造公钥。
- 密钥交换客户端生成预主密钥,用服务器公钥加密后发给服务端;服务端用私钥解密得到预主密钥。
- 生成会话密钥双方用「客户端随机数 + 服务端随机数 + 预主密钥」算出相同的对称会话密钥。
- 握手完成双方互相发送 Finished 确认,之后所有通信都用这个对称密钥加密传输。
14. 什么是前端内存泄漏?常见的内存泄露场景有哪些?
该释放的内存没被释放,一直占着不用,导致页面越用越卡、崩溃、闪退,这就是内存泄漏。
对象已经没用了,但依然被全局变量、闭包、DOM 事件等意外引用着,垃圾回收(GC)收不回去。
常见场景:
- 意外全局变量
- 未清理的事件监听
- 遗忘的定时器
- 闭包滥用
- 未释放的DOM变量
- 控制台console泄漏
- 逻辑错误,变量体积大、死循环等
- useEffect未返回清理函数(包含上述未清理问题)
15. 如何排查浏览器的内存泄漏问题?
先用 Performance 确认泄漏,再用 Memory 快照对比找到泄漏对象,通过引用链定位代码,重点查未解绑监听、定时器、DOM 引用、闭包、全局缓存。