从输入URL到前端页面渲染完成的几个步骤?
面试标准回答
- URL解析(协议、域名、端口)
- DNS解析(IP -> 域名)
- 建立TCP连接(三次握手)
- HTTPS的TLS握手
- 服务器处理并返回响应
- 浏览器解析HTML 、 CSS 、JS
- 构建渲染树并绘制页面
这个问题衍生出来了你需要去理解以下几个关键的网络传输问题,它们影响页面加载速度的原理到底是什么
以下是面试中常考的关于浏览器和计算机网络的高频内容和回答。
1. OSI七层模型
自底向上:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
2. TCP和UDP的区别
- 都是传输层协议
- 区别
| 对比 | TCP | UDP |
|---|---|---|
| 连接? | 面向连接 | 无连接 |
| 可靠? | 可靠 | 不可靠 |
| 有序? | 有序 | 无序 |
| 拥塞控制? | 有 | 无 |
| 使用场景 | HTTP/HTTPS | 视频、语音、DNS |
- TCP的拥塞控制 TCP 通过 动态调整发送速率 来避免网络拥堵。
四个核心算法
- 慢开始(Slow Start)
- 拥塞避免(Congestion Avoidance)
- 快重传(Fast Retransmit)
- 快恢复(Fast Recovery)
3.HTTP1.0-2.0的进化
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输协议 | TCP | TCP | UDP (QUIC) |
| 多路复用 | ❌ | ✅ | ✅ |
| 头部压缩 | ❌ | ✅ | ✅ |
| 队头阻塞 | 严重 | TCP层仍有 | 无 |
| 请求优先级 | ❌ | ✅ | ✅ |
| 连接建立速度 | 慢 | 慢 | 快 |
| 为什么2.0还会有队头阻塞问题? | |||
| TCP 是字节流协议,丢一个包,整个连接阻塞重传。 |
回答HTTP各版本的区别
- 1.0:默认短连接(可手动keep-alive),每个请求的成本高。
- 1.1:默认长连接,改进缓存,支持分块传输,但是仍然是文本协议,并发能力弱
- 2:实现了二进制分帧,多路复用,HPACK头部压缩,流优先级,解决了应用层的并发问题,但在TCP上仍可能因丢包产生传输层的问题
- 3:基于QUIC,集成tls1.3,更好地规避了tcp丢包的问题。
4. HTTP / HTTPS
- 区别
| 对比 | HTTP | HTTPS |
|---|---|---|
| 传输加密? | 明文传输 | 加密传输 |
| 默认端口 | 80 | 443 |
| 底层协议 | TCP | TCP+TLS |
| SEO | 一般 | 友好 |
HTTPS从信息安全的角度,有三大保证,1:机密性(加密传输); 2:完整性(哈希校验,消息认证码MAC); 3:身份认证(数字证书)
-
TCP三次握手 通过三次握手去建立一个可靠的TCP连接,确认双方的发送和接收能力都是正常的。
1:客户端向服务端发送一个SYN 2:服务端收到SYN后,返回一个SYN+ACK 3:客户端再发送ACK -
为什么不是两次握手? 两次无法确认客户端的接受能力,避免因为网络延迟造成的资源浪费。
-
SSL/TLS四次握手 在TCP的连接上,建立一个安全通信通道,协商加密方式并生成共享密钥。
以TLS1.2版本为例 1.客户端向服务端发送(TLS版本、随机数,支持的加密套件) 2.服务器发送(服务器证书(含有公钥),随机数,选的加密套件) 3.客户端校验服务端证书的合法性,并生成一个预主秘钥,用服务器公钥加密后发送给服务器 4.双方互相发送finished报文,验证握手过程未被篡改 -
TCP四次挥手 核心原因是TCP是全双工的,双方都能独立发送数据,因为连接需要将两个方向的数据通道分别安全地关闭
5.请求方法/状态码
| 方法 | 用途 | 幂等 | 是否携带 body |
|---|---|---|---|
| GET | 查询 | ✅ | ❌ |
| POST | 新增/提交 | ❌ | ✅ |
| PUT | 全量更新 | ✅ | ✅ |
| PATCH | 局部更新 | ❌/✅ | ✅ |
| DELETE | 删除 | ✅ | ❌ |
| OPTIONS | 预检 | ✅ | ❌ |
| GET 用于查询;POST 用于提交或创建资源;PUT 用于整体更新资源;DELETE 删除资源;OPTIONS 主要用于 CORS 预检。 | |||
| 状态码分为 5 类: | |||
| 1xx: | |||
| 1xx 信息性(101路由交换 | |||
| 2xx 成功(200 OK、201 创建、204 无内容), | |||
| 3xx 重定向(301 永久、302 临时、304 协商缓存命中), | |||
| 4xx 客户端错误(400 参数错误、401 未认证需要登录、403 登录但没有权限、404 资源不存在), | |||
| 5xx 服务端错误(500、502、503、504网关超时)。 |
6.跨域
跨域基于同源策略:
-
同源策略:协议 + 域名 + 端口 全部相同
-
解决方案:
-
后端方案:CORS
Access-Control-Allow-Credentials(如果要带cookie) Access-Control-Allow-Origin Access-Control-Allow-Methods Access-Control-Allow-Headers -
生产环境的方案:- Nginx 反向代理/开发代理(webpack / vite proxy),具体的
- 让前端请求同源地址:例如xxx.com/api/user
- nginx:/api转发到后端服务yyy;
-
-
预检请求:当跨域请求 不是简单请求 时,浏览器会先发送一次 OPTIONS 预检请求。
·触发预检。使用了以下方法: PUT / DELETE / PATCH / OPTIONS ·使用了非简单 Content-Type: application/json application/xml ·携带自定义请求头 -
哪些资源不会导致跨域
- “会发出去但是拿不到响应内容”:fetch/XMLHttpRequest
- 很多资源都是可以跨域加载,但有边界
/
- 表单
图片资源本身可以直接跨域加载,不会触发预检请求,也不会被浏览器拦截,但 JavaScript 默认无法读取图片内容,除非服务器配置了 CORS 允许访问。
-
postMessage
- 定义:这是浏览器提供的一种安全的跨窗口通信机制;
- 解决:完全的禁止跨域通信会限制很多合法业务,例如:第三方登录,支付嵌入,广告,埋点
7.浏览器缓存
- 啥是浏览器缓存:指浏览器将已经请求的资源存储在本地,在再次请求的时候优先使用本地副本,以减少网络请求,提升性能。由浏览器和HTTP协议自动管理。(由于开发者不可直接操作,更适合存储JS/CSS/静态资源/带hash的构建产物)
- 分类:强缓存和协商缓存
| 对比 | 强缓存 | 协商缓存 |
|---|---|---|
| 发请求? | 不发请求,直接使用缓存 | 发请求 |
| 控制字段 | cache-control(响应头):max-age-3600 /no-chache(不用强缓存)/no-store(不缓存) | Last-Modified(请求头)+If-Modified-Since(请求头) 或者 Etag(响应头) + If-None-Match(请求头) |
具体的,协商缓存中更常用的是Etag,作为资源的唯一标识,这个精度更高。 先检查强缓存,没有采带上协商缓存的字段发请求,协商缓存的流程:
1.浏览器请求带If-None-Match
2.服务器比较Etag
3.没变- 服务器返回304 Not Modified
4.变了 - 返回200 + 新资源
- 工程缓存策略
- 静态资源使用强缓存,需要文件名内容哈希,
- 入口的html要使用协商缓存no-cache,这样才能确保发版本后,用户才能拿到最新的hash文件;
- 区别js/css使用哪一种缓存,通常考虑的是资源是否版本化(带了hash),文件名带hash的css/js尽量都使用强缓存。
8.前端缓存 也放在这里和浏览器缓存进行比较
通常是cookie、localStorage、sessionStorage,这是前端用于管理用户状态和用于持久化数据的手段。
| 对比 | cookie | localStorage | sessionStorage |
|---|---|---|---|
| 请求携带? | 每次 HTTP 请求都会携带 | 不 | 不 |
| 生命周期 | 由过期时间控制 | 永久(由前端控制) | 页面关闭就消失 |
| 容量 | ~4kb | ~5MB | ~5MB |
| 跨标签页可读 | 是 | 是 | 否 |
| 使用场景 | 登录态 | 长期业务数据(用户偏好等) | 表单临时数据 |
9.平均一个网页的指标:
- Core Web Vitals:
- LCP:最大内容绘制,反应主内容加载体验:
- CLS:累积布局偏移,反映页面的稳定性;
- INP:交互到下一次绘制,反映页面的交互反应速度;
- 常用:
- FCP:首次内容绘制
- TTFB:首字节时间(反应服务端、网络质量)
10.Load和DOMContentLoaded
- DOMContentLoaded:
- 触发时机:HTML解析完成,DOM tree构建完成
- 会等待:同步脚本执行完成,defer脚本执行完成
- 不等待:图片、视频、字体、CSS背景图等加载
- 常用场景:只要能操作DOM的相关操作,例如初始化vue、绑定事件
- load(window.onload)
-
触发时机:页面上所有的资源都加载完成(DOM、图片、CSS、iframe,字体)
-
适合场景:依赖资源尺寸的逻辑、首屏截图、某些重计算,例如封面图相关的布局操作
时间 → ┌─────────────────────────── 主线程(Parser + JS)───────────────────────────┐ HTML 解析 DOM: [==========解析中==================解析完成=============] 遇到 <script async>: 标记并发起请求 (不阻塞解析) 遇到 <script defer>: 标记并发起请求 (不阻塞解析) async 执行: [==执行==] (当下载完成时,可能插队打断解析) defer 执行: [==按顺序执行==][==...==] DOMContentLoaded: | (等“解析完成 + defer执行完”) load: | (等所有资源完) └────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────────────── 网络线程(下载)───────────────────────────┐ CSS 下载: [========] async.js 下载: [====] 或者 [==============](可能快/可能慢) defer.js 下载: [=========] 图片下载: [====================] └───────────────────────────────────────────────────────────────────────┘ ┌─────────────────────────── 渲染/合成线程(Render)────────────────────┐ 样式计算/布局/绘制: [..若干次..] (会被主线程JS占用/阻塞影响时机) └───────────────────────────────────────────────────────────────────────┘
-
11.浏览器进程
1. 主进程
2. 渲染进程
3. GPU进程
4. 网络进程
5. Utility Process 音视频扩展进程