← 全部材料 浏览器
BROWSER · 14 个高频点

一次请求,要穿过多少层

浏览器这块有个特点:概念都听过,但一追问就会露馅。比如"同源策略限制什么",多数人会答"不能跨域请求"——其实它限制的是读取响应,请求本身早就发出去了。下面每一节都在纠这种半对半错的理解。

01先画流程缓存、CORS、渲染都有明确顺序,把顺序理清,细节自然就挂上去了。
02分清"拦住了什么"安全机制最容易记混:拦的是发送、读取,还是执行?问清楚这一点就不会答错。
03连到性能上缓存、渲染、事件每一节都直接影响性能,能串起来讲比单点回答更值钱。
01

从输入 URL 到页面出现★

一条链路,六个阶段
面试问"输入 URL 之后发生了什么",不要从 DNS 开始背。先给出六个阶段的骨架,再挑一个展开——这比流水账更能体现你真的理解。
解析 URL协议 / 域名 / 端口 / 路径
→
查缓存浏览器 → 系统 → 路由
→
建立连接DNS → TCP → TLS
→
发请求HTTP 报文 + Cookie
→
解析渲染HTML → DOM,CSS → CSSOM
→
加载子资源JS / 图片 / 字体
面试怎么答整体链路是:解析 URL → 各级缓存 → DNS 解析 → TCP 三次握手 → TLS 握手 → 发送 HTTP 请求 → 接收响应 → 解析 HTML 构建 DOM 和 CSSOM → 布局绘制 → 加载子资源并执行 JS。面试时给出这个骨架,然后挑 DNS 或 TLS 深入。
02

浏览器不是一个进程★

one tab can crash without taking the browser down
Chrome 是多进程架构,不是"一个程序跑一个页面"。拆开的核心动机只有三个: 一个页面崩了别把整个浏览器带走(稳定性)、把渲染进程关进沙箱(安全)、 让多个页面真正并行(性能)。代价是内存占用高——这也是它被叫"内存杀手"的原因。
五个主要进程,各自负责什么 浏览器主进程:只有一个。管窗口、标签页、地址栏、前进后退、以及所有其他进程的创建和调度。
渲染进程:每个标签页一个(严格说是每个站点实例一个)。负责 HTML 解析、样式计算、布局、绘制、执行 JS。前端代码全跑在这里。
GPU 进程:只有一个。负责合成层、3D 变换、硬件加速。
网络进程:负责所有网络请求。以前在浏览器进程里,现在独立出来。
插件进程:每个插件一个,用完就退。

✕ 常见误解

  • "一个标签页就是一个进程" —— 同站点的 tab 可能合并
  • "多进程是为了快" —— 主要是为了稳定和安全,性能是副产品
  • "JS 单线程所以浏览器是单线程" —— 浏览器内部线程非常多

最后一条最容易答错:说"JS 是单线程"指的是每个渲染主线程只有一个 JS 执行栈,不是整个浏览器只有一个线程。

✓ 面试可以补的一句

  • 进程间靠 IPC 通信,所以跨进程的 DOM 操作代价很高
  • 合成线程能独立处理滚动,所以 transform 动画不掉帧
  • Web Worker 是渲染进程内的线程,共享进程内存但不共享执行栈

把这三点说出来,说明你理解的是"线程模型",而不是背了个"多进程"的名词。

面试这样答
Chrome 采用多进程架构,主要有五类进程:浏览器主进程负责窗口和标签页管理、渲染进程负责解析 HTML、计算样式、布局绘制和执行 JS、GPU 进程负责合成和硬件加速、网络进程负责请求、插件进程。拆成多进程主要是为了三点:一是稳定性,单个页面崩溃或 OOM 不会影响其他标签页;二是安全,渲染进程跑在沙箱里,不能直接访问系统资源,需要特权的操作都要通过 IPC 请求主进程;三是性能,多个页面可以真正并行。渲染进程内部还是多线程的,主线程负责解析、布局和 JS 执行,合成线程负责滚动和合成动画,所以 transform 动画能脱离主线程独立跑而不掉帧。JS 所谓的单线程,指的是渲染主线程只有一个 JS 执行栈,不是整个浏览器单线程。
03

HTTP 缓存:强缓存与协商缓存★

为什么改了代码要带 hash
强缓存命中时根本不发请求,直接读本地;协商缓存要发一次请求,服务端说"没变"就回 304、不传内容。前者快但难更新,后者能及时更新但多一次往返。
实际策略几乎都长这样 index.html Cache-Control: no-cache 每次都协商,保证拿到新入口 main.[hash].js Cache-Control: max-age=31536000, immutable 一年,永不失效 文件名带 hash → 内容变则文件名变 → 天然不需要"清缓存"
面试怎么答强缓存靠 Cache-Control 的 max-age 和 immutable,命中时不发请求;协商缓存靠 ETag/Last-Modified,服务端比较后返回 304。工程上的标准做法是 HTML 用 no-cache 保证入口可更新,静态资源用内容 hash 加一年的 max-age。
04

HTTP/1.1 → 2 → 3:三个层次的队头阻塞★

每次升级都在解同一个问题
队头阻塞其实有三层:应用层(同域并发限制)、HTTP 层(响应必须按序)、TCP 层(丢包会阻塞所有流)。1.1 卡在第一层,2 解决了前两层,3 换 UDP 才彻底解决第三层。
HTTP/1.1每域 6 个并发,排队等
→
HTTP/2一个 TCP 连接多路复用
→
HTTP/3QUIC over UDP,流之间互不影响

HTTP/2 带来的

  • 头部压缩(HPACK),省掉重复的 Cookie 和 UA
  • 多路复用,一个连接并发跑所有请求
  • 服务端推送(实际已被废弃)

HTTP/2 没解决的

  • 单个流的阻塞仍会拖累整条连接
  • 每丢一个包,所有流一起等
  • 所以弱网下 2 有时比 1.1 还慢
面试怎么答队头阻塞分三层:HTTP/1.1 受同域并发数限制;HTTP/2 用多路复用解决了应用层和 HTTP 层的队头,但底层共用一个 TCP 连接,丢包时所有流都被阻塞;HTTP/3 改用 QUIC over UDP,每个流独立重传,才彻底解决。
05

同源策略与 CORS★

同源策略限制的是"读",不是"发"
同源策略不阻止请求发出,它阻止的是读取响应。所以 POST 请求其实已经到达服务端并执行了——这也是 CSRF 能成立的原因。
什么情况不触发预检(简单请求) 满足这三个条件才是简单请求,直接发送、不预检: 方法 ∈ { GET, HEAD, POST } 头都是安全列表内的(Accept / Accept-Language / Content-Language / Content-Type) Content-Type ∈ { text/plain, multipart/form-data, application/x-www-form-urlencoded } application/json 不在名单里 → 一定预检
面试怎么答同源策略限制的是跨源读取响应和访问 DOM,不限制请求发送。CORS 通过响应头授权,非简单请求会先发 OPTIONS 预检。带凭证时 Allow-Origin 不能是通配符,必须回具体源并允许 credentials。
06

Cookie、Storage、IndexedDB 怎么选★

容量、生命周期、是否自动携带
三者的分界线很清楚:Cookie 会被每次请求自动带上(所以只能存少量身份信息),localStorage 同步阻塞(别存大对象),IndexedDB 异步大容量(适合离线数据)。

localStorage 的代价

  • 同步 API,读写会阻塞主线程
  • 只有字符串,存对象要 JSON 序列化
  • 同源共享,标签页之间会互相覆盖
  • 5MB 左右上限,超了直接抛异常

IndexedDB 适合的

  • 结构化数据、二进制 Blob
  • 异步,不阻塞渲染
  • 支持索引和事务查询
  • 容量按磁盘配额,通常几百 MB
面试怎么答Cookie 4KB、每次请求自动携带,适合存会话标识,配合 HttpOnly 和 Secure 使用。localStorage 约 5MB、同步、跨标签共享,适合存轻量偏好。sessionStorage 只在当前标签页。IndexedDB 异步、容量大、支持索引,适合离线数据和大对象。
07

XSS:三种类型与三层防御★

为什么"过滤关键词"永远不够
XSS 的本质是把数据当成了代码。防御不能靠黑名单过滤,要靠按上下文转义 + CSP 兜底 + HttpOnly 减少损失。
输入校验白名单,但只是第一层
→
输出转义按上下文转义,最关键的一层
→
CSP禁止内联脚本,兜底
→
HttpOnly就算被注入也偷不到 Cookie
面试怎么答XSS 分存储型、反射型、DOM 型,本质是把不可信数据当代码执行。防御按层来:输入做白名单校验,输出按上下文转义,用 CSP 禁止内联脚本兜底,Cookie 加 HttpOnly 限制被窃取的后果。DOM 型要避免把用户输入塞进 innerHTML。
08

CSRF 与 SameSite★

借你的登录状态,替你做请求
CSRF 能成立的前提是浏览器会自动带上 Cookie。所以防御的核心不是"识别用户",而是识别这个请求是不是用户自愿发的——用 token 或 Origin 校验。

不够的防御

  • 只校验 Cookie 是否存在
  • 用 GET 做写操作(连表单都不用)
  • 把 token 放在 URL 里(会进日志和 Referer)

有效的防御

  • SameSite=Lax / Strict
  • CSRF token(一次性,服务端校验)
  • 校验 Origin / Referer
  • 敏感操作二次验证
面试怎么答CSRF 是利用浏览器自动携带 Cookie 的特性,诱导用户在自己已登录的站点上发起非预期请求。防御手段是 SameSite Cookie、CSRF token、校验 Origin/Referer,以及敏感操作二次验证。写操作不能用 GET。
09

渲染流程:五步,不是三步★

从 DOM 到屏幕上的像素
明确五步:构建 DOM 和 CSSOM → 合成渲染树 → 布局(Layout)→ 绘制(Paint)→ 合成(Composite)。JS 会阻塞 DOM 构建,CSS 会阻塞渲染树,这两条决定了优化方向。
DOM + CSSOM两棵树分别构建
→
Render Tree只含可见节点
→
Layout算位置和尺寸
→
Paint画成图层位图
→
Composite合成到屏幕
面试怎么答渲染分五步:解析 HTML 生成 DOM、解析 CSS 生成 CSSOM、合成只含可见节点的渲染树、计算布局、绘制并合成图层。CSS 阻塞渲染,JS 阻塞 DOM 解析,布局是最昂贵的一步。
10

重排、重绘与合成层★

改哪个属性,决定了要重走几步
改几何属性触发重排(最贵),改颜色触发重绘,改 transform/opacity 只触发合成(最便宜)。这就是"动画只用 transform"的全部理由。
◐ 可交互:同样是把方块挪过去,代价差十几倍
点一下,看它触发了哪些阶段
累计次数
回流 layout0
重绘 paint0
合成 composite0
估算主线程耗时 0 ms
三种改法在代码上几乎一样长,但走的流水线完全不同。

会触发重排(Layout)

  • width / height / padding / margin
  • top / left / position
  • font-size / line-height
  • 读 offsetTop / getBoundingClientRect(强制同步布局)

只触发合成(Composite)

  • transform: translate / scale
  • opacity
  • filter(部分场景)
  • 前提是元素在独立图层上
面试怎么答改几何属性触发重排,改绘制属性触发重绘,改 transform 和 opacity 只走合成。性能优化的关键是把读操作和写操作分开,避免强制同步布局;动画优先用 transform,必要时用 will-change 提前提层但要注意内存代价。
11

事件:捕获、冒泡与 passive★

为什么滚动回调里不能随便 preventDefault
DOM 事件分三个阶段:捕获 → 目标 → 冒泡。事件委托利用冒泡把监听挂在父元素上。passive: true 让浏览器不必等回调执行完就能开始滚动。
为什么 passive 影响这么大 浏览器默认要等 touchmove 回调执行完, 才知道你会不会 preventDefault 阻止滚动。 回调里只要有一次同步计算耗时 100ms, 滚动就卡 100ms。 passive:true 之后浏览器直接开始滚, 不等回调。代价是回调里再调 preventDefault 会失效(并有警告)。
面试怎么答事件流是捕获、目标、冒泡三个阶段。事件委托利用冒泡在父元素统一处理,减少监听数量。passive 告诉浏览器回调不会阻止默认行为,让滚动不必等待 JS,这是移动端滚动性能的关键优化。
12

Service Worker 与离线缓存

一个跑在页面之外的代理
Service Worker 是独立于页面的线程,能拦截该作用域下所有请求。它的价值不在"离线",而在把缓存策略变成代码——你能决定每个请求怎么取。
四种常用策略,按资源类型选 Cache First HTML/CSS/JS/字体 命中缓存就走,适合带 hash 的静态资源 Network First 接口数据 先请求,失败回退缓存,适合时效性强的 Stale While Revalidate 头像、列表 先给旧的,同时后台更新 Network Only 支付、登录 绝不缓存
面试怎么答Service Worker 是独立线程,可以拦截作用域内的网络请求,实现离线缓存和自定义缓存策略。生命周期是 install、activate、fetch 三个阶段,要注意预缓存、清理旧版本和 skipWaiting 的更新问题。必须在 HTTPS 下运行。
13

安全响应头:几行配置挡住一大类攻击

比在代码里逐处防御更可靠
安全头属于兜底防线:代码里的转义可能漏,但 CSP 只要配对了,注入的脚本就是跑不起来。
面试怎么答常见安全头:HSTS 强制 HTTPS、CSP 限制资源来源并禁止内联脚本、X-Content-Type-Options 禁止 MIME 嗅探、X-Frame-Options 防点击劫持、Referrer-Policy 控制信息泄露。CSP 上线前应该用 Report-Only 模式观察。
14

Performance API 与页面生命周期

别靠猜,浏览器自己会报
所有性能指标的真实来源都是 Performance API。理解它,就不用背"某个指标怎么算"——你能自己取。
面试怎么答Performance API 提供导航时间、资源加载、自定义 mark/measure,以及 PerformanceObserver 用来收集 LCP、CLS、INP 等指标。页面生命周期用 visibilitychange 判断页面是否可见,上报数据用 sendBeacon,避免用 unload 因为它会破坏 bfcache。
15

HTTP 状态码与请求方法★

面试里最爱考的十几个
状态码分五类,首字母就是类别:1 信息、2 成功、3 重定向、4 客户端错、5 服务端错。真正需要背熟的是十几个高频码,尤其301 与 302、304、401 与 403、502 与 504 这几对。
高频状态码,按"容易混"分组【重定向】 301 永久重定向,浏览器和搜索引擎都会缓存,慎用 302 临时重定向,每次都会重新请求 307 临时重定向,且保证方法和 body 不变(POST 还是 POST) 308 永久重定向,且保证方法不变 坑:301 缓存后用户改不回来,测试环境别用 301 【缓存】 304 Not Modified,协商缓存命中,响应没有 body 【客户端错】 400 请求参数有问题 401 未认证(没登录、token 过期) 403 已认证但无权限(登录了但没这个权限) 404 资源不存在 405 方法不允许(接口只支持 POST,用了 GET) 409 冲突(并发修改、唯一键重复) 422 参数格式对但语义不合法(校验失败常用) 429 请求太频繁,被限流 【服务端错】 500 代码抛异常 502 Bad Gateway,网关拿到上游的无效响应(上游进程挂了) 503 Service Unavailable,服务暂时不可用(过载、发布中) 504 Gateway Timeout,网关等上游超时
面试怎么答状态码按首位分五类。高频里最容易混的是三对:401 是未认证,403 是已认证但无权限,把 403 写成 401 会让用户被反复踢出登录;502 是网关拿到上游的无效响应通常是上游进程挂了,504 是网关等上游超时,所以 502 查进程、504 查为什么慢;301 是永久重定向会被浏览器缓存,测试环境用 302 或 307 更安全。另外方法的幂等性决定了能不能自动重试,POST 不幂等,重试可能重复下单。
16

跨域:五种方案和前三种的死因★

CORS 只是其中一种
同源是协议 + 域名 + 端口三者全同。跨域限制是浏览器执行的,服务端之间调用不受限。五种方案:CORS、代理、JSONP、postMessage、WebSocket。现代项目 95% 用前两种,后三种各有明确的历史原因。
五种方案各自的适用面【CORS】服务端加响应头,正道 Access-Control-Allow-Origin: https://a.com Access-Control-Allow-Credentials: true 带 Cookie 时 Origin 不能写 *,必须写具体域名 非简单请求会先发 OPTIONS 预检 【代理】开发用 devServer,生产用 Nginx 开发:vite 的 server.proxy / webpack 的 devServer.proxy 生产:Nginx 把 /api 转发到后端,浏览器看来是同源 优点:不用改后端,也不会有预检 这是企业项目最常用的做法 【JSONP】只支持 GET,靠 script 标签不受同源限制 服务端返回 callback({...}) 死因:只能 GET、没有错误处理、有 XSS 风险 现在只存在于老接口 【postMessage】iframe 父子页面通信 跨域 iframe 之间唯一可靠的方式 必须校验 event.origin,否则等于开放给任何页面 【WebSocket】不受同源策略约束 但这不代表安全,服务端必须自己校验 Origin
面试怎么答同源是协议、域名、端口全同,跨域限制由浏览器执行,服务端之间调用不受限。五种方案里 CORS 是正道,服务端加响应头,非简单请求会先发 OPTIONS 预检;代理是开发用 devServer、生产用 Nginx 转发,浏览器看来同源,所以企业项目最常用;JSONP 只能 GET 且没有错误处理已经基本淘汰;postMessage 用于跨域 iframe 通信,必须校验 origin;WebSocket 不受同源约束但服务端要自己校验 Origin。带 Cookie 时 Allow-Origin 不能写星号。
17

速答清单

考前十分钟只看这页
01输入 URL 之后发生了什么?
解析 URL → 各级缓存 → DNS → TCP 握手 → TLS → HTTP 请求 → 解析构建 DOM/CSSOM → 布局绘制 → 加载子资源。挑 DNS 或 TLS 展开。
02强缓存和协商缓存?
强缓存 Cache-Control: max-age 命中不发请求;协商缓存靠 ETag 返回 304。工程上 HTML 用 no-cache,资源用 hash + 一年。
03no-cache 和 no-store?
no-cache 可以存但用前必须校验;no-store 完全不许存。
04HTTP/2 解决了什么,没解决什么?
解决了应用层队头阻塞(多路复用)和头部冗余(HPACK),但共用一个 TCP 连接,丢包仍会阻塞所有流。
05同源策略限制什么?
限制跨源读取响应和访问 DOM,不限制请求发送——这是 CSRF 成立的前提。
06XSS 怎么防?
按上下文转义 + CSP 禁止内联脚本 + Cookie 加 HttpOnly。别靠关键词过滤。
07CSRF 怎么防?
SameSite Cookie、CSRF token、校验 Origin/Referer。写操作不能用 GET。
08渲染五步?
DOM/CSSOM → 渲染树 → 布局 → 绘制 → 合成。CSS 阻塞渲染,JS 阻塞 DOM 解析。
09为什么动画用 transform?
只触发合成,跳过布局和绘制。改 width/top 会触发重排,代价最大。
10passive 有什么用?
告诉浏览器回调不会 preventDefault,滚动不必等 JS 执行完,移动端滚动性能的关键。
11浏览器为什么要用多进程架构?
三个原因:稳定性,一个页面崩溃或 OOM 不会影响其他标签页;安全,渲染进程跑在沙箱里,需要特权的操作都要通过 IPC 请主进程代办;性能,多个页面可以真正并行。代价是每个进程都要带一份引擎基础开销,内存占用高。
12一个标签页就是一个进程吗?
不严格。Chrome 会做进程复用,同一个站点的多个标签页可能共享一个渲染进程以省内存;不同站点则强制隔离,这是 Site Isolation 策略。跨站的 iframe 也会被放进独立进程,父子之间只能 postMessage。
13JS 是单线程的,那浏览器也是单线程吗?
不是。浏览器是多进程的,渲染进程内部也是多线程的:主线程负责解析、样式、布局和 JS 执行,合成线程负责滚动和合成动画,还有光栅线程和若干 Worker 线程。说 JS 单线程指的是每个渲染主线程只有一个 JS 执行栈。
14为什么 transform 动画比改 left 更流畅?
因为 transform 的合成可以在合成线程完成,不占用主线程。改 left 会触发布局和重绘,必须回到主线程算,JS 一忙就掉帧。