浏览器原理常用来判断你是否只会写业务,还是理解页面从输入 URL 到展示、交互、优化的完整链路。

浏览器架构

多进程模型

知识点讲解

现代浏览器通常包含浏览器进程、网络进程、GPU 进程、渲染进程、插件进程等。每个标签页一般会有独立渲染进程,隔离页面执行环境,提高稳定性和安全性。

面试常问

问:为什么浏览器要多进程?

答:主要是稳定性、安全性和性能隔离。某个页面崩溃不至于拖垮整个浏览器,不同站点之间也能做更好的安全隔离。

从输入 URL 到页面展示

知识点讲解

核心流程是:URL 解析、缓存检查、DNS 解析、TCP/TLS 握手、发送 HTTP 请求、接收响应、解析 HTML、构建 DOM 和 CSSOM、合成 Render Tree、Layout、Paint、Composite。

面试常问

问:输入 URL 后发生了什么?

答:先从网络链路讲到资源获取,再从渲染链路讲到页面展示。回答时不要只背步骤,要补充缓存、重定向、HTTPS、关键渲染路径和性能优化点。

渲染流水线

DOM、CSSOM 与 Render Tree

知识点讲解

HTML 解析生成 DOM,CSS 解析生成 CSSOM。两者合并形成 Render Tree,但 display: none 的节点不会进入 Render Tree。随后浏览器计算布局、绘制像素、最后合成图层。

面试常问

问:CSS 会阻塞渲染吗?

答:会。浏览器需要 CSSOM 才能计算最终样式,所以 CSS 是渲染阻塞资源。JS 如果访问样式或 DOM,也可能被 CSS 阻塞。

重排、重绘与合成

知识点讲解

重排是重新计算布局,成本较高;重绘是重新绘制外观;合成是把已有图层交给合成线程处理。动画优先使用 transformopacity,因为更容易走合成路径。

面试常问

问:如何减少重排?

答:批量读写 DOM、避免频繁访问触发布局的属性、使用 class 批量改样式、复杂动画用 transform、离线操作 DOM、列表虚拟化。

V8 与 JS 执行

编译与执行

知识点讲解

V8 会把 JS 解析成 AST,再生成字节码执行,热点代码会被 JIT 优化成机器码。对象形状稳定、类型稳定的代码更容易优化;频繁改变对象结构会影响性能。

面试常问

问:为什么说 JS 是解释型语言但也有编译?

答:现代 JS 引擎不是简单逐行解释。它会先解析、生成中间表示和字节码,并对热点代码做即时编译优化。

垃圾回收

知识点讲解

GC 主要判断对象是否仍可达。常见算法有标记清除、分代回收。新生代对象生命周期短,回收频繁;老生代对象存活久,回收成本更高。

面试常问

问:前端常见内存泄漏有哪些?

答:未清理定时器、事件监听、闭包长期持有大对象、缓存无限增长、DOM 被移除但仍被 JS 引用。

存储、安全与性能

浏览器存储

知识点讲解

Cookie 适合随请求携带少量数据;LocalStorage 同源持久存储,容量有限且同步阻塞;SessionStorage 随标签页生命周期;IndexedDB 适合大量结构化数据;Cache API 常配合 Service Worker 做离线缓存。

面试常问

问:Cookie、LocalStorage、SessionStorage 区别?

答:Cookie 会随请求发送,适合认证标识但要注意安全属性;LocalStorage 持久保存;SessionStorage 关闭标签页失效。敏感 token 不建议直接放 LocalStorage。

XSS、CSRF 与 CORS

知识点讲解

XSS 是攻击者注入脚本,防护重点是输入校验、输出转义、CSP、避免危险 API。CSRF 是利用用户登录态伪造请求,防护重点是 SameSite Cookie、CSRF Token、校验 Origin/Referer。CORS 是浏览器的跨域访问控制机制,不是服务器之间的限制。

面试常问

问:CORS 预检请求是什么?

答:复杂请求前浏览器会先发 OPTIONS 请求,询问服务端是否允许真实请求。服务端返回允许的方法、头和源后,浏览器才继续发送真实请求。

性能优化

知识点讲解

性能可以按加载、渲染、运行时拆解。加载侧关注缓存、CDN、压缩、代码分割、预加载;渲染侧关注关键 CSS、减少阻塞、图片优化;运行时关注长任务、虚拟列表、Web Worker、防抖节流。

面试常问

问:白屏时间怎么优化?

答:减少关键资源体积,启用缓存和 CDN,SSR/SSG,关键 CSS 内联,路由级代码分割,图片懒加载,压缩资源,减少首屏不必要 JS。

底层追问与代码示例

强制同步布局

知识点讲解

浏览器为了性能会批量处理样式计算和布局。如果代码先写 DOM,再立即读布局属性,浏览器必须提前刷新布局,这叫 forced synchronous layout。

1
2
3
4
5
6
7
const box = document.querySelector('.box')

// 写
box.style.width = '300px'

// 立刻读,会迫使浏览器同步计算布局
console.log(box.offsetWidth)

更好的方式是把读写分离:

1
2
3
4
5
6
7
8
9
const boxes = [...document.querySelectorAll('.box')]

const widths = boxes.map(box => box.offsetWidth)

requestAnimationFrame(() => {
boxes.forEach((box, index) => {
box.style.transform = `translateX(${widths[index]}px)`
})
})

面试常问

问:哪些属性会触发布局读取?

答:常见有 offsetWidthoffsetHeightclientWidthscrollTopgetBoundingClientRect()getComputedStyle() 等。它们可能要求浏览器拿到最新布局结果。

长任务与主线程阻塞

知识点讲解

浏览器主线程负责 JS 执行、样式计算、布局、绘制和用户事件。单个任务超过 50ms 通常会被视为 Long Task,可能导致输入延迟和卡顿。

1
2
3
4
5
6
7
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.log('long task:', entry.duration)
}
})

observer.observe({ entryTypes: ['longtask'] })

拆分长任务可以使用 requestIdleCallback 或分片调度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function runChunks(items, handler, chunkSize = 500) {
let index = 0

function work() {
const end = Math.min(index + chunkSize, items.length)
while (index < end) {
handler(items[index], index)
index += 1
}

if (index < items.length) {
setTimeout(work, 0)
}
}

work()
}

缓存策略:强缓存与协商缓存

知识点讲解

强缓存命中时不会请求服务器,核心响应头是 Cache-ControlExpires。协商缓存会请求服务器验证资源是否变化,核心是 ETag / If-None-MatchLast-Modified / If-Modified-Since

1
2
Cache-Control: public, max-age=31536000, immutable
ETag: "app.8f3a1.js"

生产实践:

  • JS/CSS 使用内容哈希文件名,配合长期强缓存。
  • HTML 不做长期强缓存,避免引用旧资源。
  • 图片和字体按更新频率设置缓存。

面试常问

问:ETag 和 Last-Modified 谁更准?

答:ETag 更准。Last-Modified 只能精确到秒,且依赖文件修改时间;ETag 可以基于内容生成,更适合判断资源是否真的变化。

Service Worker 缓存

知识点讲解

Service Worker 是浏览器和网络之间的代理层,可以拦截请求并自定义缓存策略。常见策略有 Cache First、Network First、Stale While Revalidate。

1
2
3
4
5
6
7
8
9
10
11
12
13
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cache => {
return cache || fetch(event.request).then(response => {
const cloned = response.clone()
caches.open('static-v1').then(cacheStore => {
cacheStore.put(event.request, cloned)
})
return response
})
})
)
})

面试里要补一句:Service Worker 必须在 HTTPS 或 localhost 下运行,并且更新策略要谨慎,否则可能缓存旧版本。