面试备战录

90 阅读6分钟

1、浏览器从输入 URL 到页面渲染完成,发生了什么?

当输入 URL并回车后,浏览器会先解析URL并查缓存,若未命中则进行 DNS 解析、TCP 三次握手(HTTPS 还要进行 TLS 握手),然后发出HTTP请求,服务器返回HTML。浏览器从流式HTML解析构建DOM,同时并下载解析CSS构建CSSDOM,合并成渲染树,经过布局、绘制、合成后显示页面。过程中JS会阻塞解析,CSS会阻塞渲染。性能优化可从减少请求数、压缩资源、利用缓存、优化关键渲染路径等方面入手。

具体步骤:

  1. 输入 URL → 请求发出
  • 解析 URL:拆分协议(HTTP/HTTPS)、域名、端口、路径、查询参数等
  • 浏览器检查缓存(强缓存):Memory Cache(内存缓存)Disk Cache(硬盘缓存),如果命中Cache-Control: max-age 或 Expires,直接用缓存,跳过网络请求。
  • DNS 解析:
    • 将域名解析为 IP(可能走本地缓存/系统缓存/DNS服务器)
    • 支持DNS Prefetch提前解析
  • TCP 三次握手:建立连接(如果是 HTTPS,还要进行TLS握手
  • 发送HTTP请求:请求行 + 请求头(Cookie、User-Agent 等);GET/POST 等方法
  • 服务器处理并返回响应:响应头(状态码、缓存策略、内容类型);响应体(HTMLJSON、图片等)
  • 协商缓存(如命中ETagLast-Modified
  1. 浏览器解析 HTML
  • 构建 DOM 树
    • 按字节流解析 HTML → Token → Node → DOM
    • 遇到 CSS/JS 会影响解析:
      • CSS:不会阻塞 DOM 构建,但会阻塞渲染
      • JS:默认阻塞 DOM 解析(除非加 defer/async)
  • 构建 CSSOM(CSS 对象模型)
    • 解析外部 CSS 文件、<style>、行内样式
    • CSS 下载是异步的,但渲染前必须完成
  • 合并 DOM + CSSOM → Render Tree(渲染树)
  1. 布局与绘制
  • 布局(Layout / Reflow)
    • 根据渲染树计算每个元素的位置和大小
  • 绘制(Paint)
    • 将每个节点绘制成像素
  • 合成(Composite Layers)
    • 将不同图层合成,利用GPU加速
    • 触发机制:position: fixed、transform、will-change
  1. JS 执行与交互
  • 遇到 <script> 会进入JS引擎执行
  • 如果JS修改了DOM/CSS,可能触发重排(Reflow)重绘(Repaint)
  1. 性能优化可切入的点
  • 减少DNS查询 → DNS 预解析(<link rel="dns-prefetch">)
  • 减少HTTP请求数 → 合并资源、使用HTTP/2
  • 压缩资源 → gzip/brotli
  • 利用缓存 → Cache-ControlETag
  • 优化关键渲染路径 → Critical CSS首屏SSR
  • 异步加载JSdefer/async
  • 懒加载资源 → 图片、非首屏模块懒加载

2、浏览器的渲染流程是怎样的?

  • 解析HTML → 构建DOM树
    • 浏览器的HTML解析器按字节流读取HTML
    • 转成Tokens(标签、文本、注释等)
    • 再转成DOM节点对象
    • 依次插入形成DOM Tree(文档对象模型),遇到<script>(无 defer/async)会阻塞HTML解析
    • 遇到外部CSS会阻塞后续JS执行(因为JS可能依赖样式信息)
  • 解析CSS → 构建CSSOM
    • 下载外部CSS 文件(并解析<style>标签行内样式
    • 将选择器解析成节点规则,形成 CSS Object Model
    • CSSOMDOM是两棵独立的树,CSSOM是渲染的必要条件,它会阻塞首次渲染
  • 合并 DOM + CSSOM → Render Tree(渲染树),这棵树是后续布局和绘制的基础
    • 渲染树包含:DOM中的可见节点(display: none的不会进来);每个节点的计算后样式(Computed Style
  • Layout(布局 / 回流)
    • 根据渲染树计算每个节点的:坐标位置(x/y)尺寸(width/height)
    • 结果是一个带有几何信息的布局树
      • 触发 Layout 的典型情况:DOM结构变化(增加/删除节点);元素尺寸、位置变化;浏览器窗口尺寸变化
  • Paint(绘制)
    • 根据布局结果,把元素的文字、颜色、边框、阴影、背景图等画到位图中
    • 每个图层分别绘制:触发Paint(但不回流)的情况:color、background-color、box-shadow 等改变
  • Composite(合成)
    • 把多个图层(Layer)交给 GPU 合成
    • 利用 硬件加速 渲染到屏幕
    • 涉及滚动、CSS 动画、3D 变换等

注:HTML 和 CSS 解析是并行的,是在两个线程中进行解析的

3、浏览器的主线程负责哪些事情?还有哪些辅助线程?

答:主线程是“大脑”,管 DOM、CSSOM、JS、布局、绘制;其他线程是“手脚”,管下载、计时、事件、GPU、计算

  1. 主线程(Main Thread):主线程基本上是浏览器渲染引擎的“大脑”,它会串行执行这些核心任务:
  • HTML解析
    • HTML Parser执行
    • HTML转换为 DOM 树
    • 解析过程中遇到<script>、<link>、<style>会交给对应模块处理
  • CSS解析
    • 有时主线程直接解析 CSS(小型/内联 CSS)
    • 大型 CSS 文件可能交给后台线程(多线程解析)
  • JavaScript执行
    • 调用JS 引擎(V8)
    • 执行所有脚本(同步、异步回调、事件处理)
  • 样式计算(Style)
    • CSS选择器匹配到DOM元素
    • 生成计算样式(Computed Styles)
  • 布局(Layout / Reflow)
    • 根据DOM + CSSOM计算每个元素的位置和大小
  • 绘制(Paint)& 合成(Composite)
    • 绘制各个元素的位图
    • 调用GPU线程进行合成

4、什么是 Event Loop?微任务和宏任务分别是什么?它们的执行顺序?

答:Event Loop(事件循环) 是浏览器(或 Node.js)协调 同步任务异步任务 执行顺序的机制。它的核心作用是:

  • 同步任务 直接在主线程执行(调用栈中执行)
  • 异步任务(定时器回调、事件回调、Promise 等)被放入不同的任务队列
  • 主线程空闲时,从任务队列取任务执行 → 这个不断循环的过程就是 Event Loop

宏任务(Macro Task):宏任务是一类大任务,每次执行时会完整地执行一段独立的代码,然后再进入下一轮循环。常见宏任务:setTimeoutsetIntervalsetImmediate(Node.js)I/O 操作UI 渲染任务整个 script 脚本(第一次执行也算一个宏任务)

微任务(Micro Task):微任务是更细粒度的任务,它们会在当前宏任务结束后、下一个宏任务开始前立即执行。常见微任务:Promise.then/catch/finallyMutationObserverqueueMicrotask

执行顺序

  • 执行一个宏任务(可能是 script 整体、setTimeout 回调等)
  • 执行完当前宏任务后,立刻执行所有微任务(直到清空微任务队列)
  • 渲染 UI(如果需要)
  • 进入下一轮宏任务 -> 先宏任务,后微任务;微任务全部执行完才进入下一轮宏任务。script 整体是第一个宏任务,Promise是微任务,setTimeout是下一个宏任务。

5、页面中的 JavaScript 执行会阻塞哪些阶段?为什么?

  • 阻塞HTML解析:
    • 同步<script>标签会暂停HTML解析,先下载并执行JS,再继续解析。
    • 原因:JS可能调用document.write()修改 DOM,影响后续解析内容。
  • 阻塞CSSOM构建(间接影响JS执行)
    • 如果JS在执行前需要读取样式信息(如 getComputedStyle、布局数据),而CSS还没解析完成,JS必须等待CSS加载并构建CSSOM
    • 原因:保证样式数据是最新的,避免渲染结果错乱。
  • 阻塞渲染(Layout / Paint)
    • JS修改DOM或样式后,如果立即读取布局信息(如 offsetHeightscrollTop),会触发强制同步布局,阻塞渲染流水线。
    • 原因:浏览器必须立刻计算布局才能返回正确值。