从输入url到浏览器完成页面渲染,这期间发生了什么 📅 2026/7/17 11:54:26 目录相关进程具体步骤一 url解析二 发起请求三 准备渲染进程四 提交响应数据五 渲染总结根据之前看的很多文章和做的一点笔记还是打算整理整理做个总结。其中对渲染前的很多准备工作也进行了详述涉及一些计算机网络知识、操作系统知识只做了解即可。整体分成五步1解析url2网络请求由网络进程发起请求资源和接收数据3准备渲染浏览器给页面分配渲染进程并初始化一些准备工作4提交响应数据网络进程将响应数据传输给渲染进程且浏览器进程会更新页面状态5渲染构建DOM树、计算样式、计算布局、进行绘制、合成显示都由渲染进程完成其中最复杂的就是渲染这一步花了最多篇幅详述整个渲染过程可着重研究这一步。第2步网络请求这里涉及dns查询、建立tcp连接这些知识也是前端经常考查的知识。相关进程在整个过程中涉及以下三个进程三个进程之间交互完成所有工作浏览器进程网络进程渲染进程具体步骤一 url解析在地址栏输入url地址后该内容首先被地址栏解析解析由浏览器进程下面的UI线程负责。具体解析流程二 发起请求首先经过解析后的url地址会被浏览器进程以进程间通信的方式发送给网络进程1 网络进程收到http请求后1首先会检查本地缓存是否存在该资源如果存在则直接将该资源返回给浏览器进程那么该次url导航也就结束了2如本地缓存中不存在该资源网络进程才会正式发起http请求http请求的具体过程i. DNS查询计网知识就不详细展开了主要就是递归与迭代配合的方式进行查询ii. DNS查询结束后获取到了对应ip这时候就开始建立TCP请求了如果请求协议是https在此之前还要建立TLS连接iii. 建立完连接浏览器端会构建请求行、请求头等信息如果有相关的cookie根据实际会将cookie数据添加到请求头中iv. 准备完成开始发送请求服务器收到请求后会根据请求信息生成响应数据然后发送给网络进程成功的话2 网络进程接收到服务器发来的响应数据后如果状态码是301或302则表示重定向网络进程根据响应头中的Location字段该字段就是重定向的url重新发起http请求没错重新来一遍如果状态码是200那么说明请求资源成功并且成功接收了成功接收到服务器返回的响应数据还得判断返回的数据类型http头中的Content-Type字段会指明返回的响应数据是什么类型Content-Type字段举例text/plain 代表这是普通文本不会产生HTML解析text/html 代表这是HTML格式内容就是要进行渲染的所依据的HTML字节流application/octet-stream 代表这是字节流类型通常浏览器将其视作下载类型处理如果响应数据被判断为下载类型那么浏览器会将其交给下载管理器处理那么这次url导航就结束了如果是HTML格式的内容接下来浏览器就该准备渲染工作了三 准备渲染进程以Chrome为例浏览器默认情况下会为每个页面分配一个渲染进程所以说每打开一个页面这个页面也就获得了一个渲染进程当然也有例外当两个页面从属于一个站点时同站点即这两个页面的url协议一样根域名也一样那么这两个页面就从属于同一个站点后打开的页面会复用先打开的页面的渲染进程。渲染进程准备完毕后就等着响应数据提交过来因为现在响应数据还在网络进程里然后开始渲染工作。四 提交响应数据这里又要涉及进程间通信1 网络进程收到响应数据后会告知浏览器进程然后由浏览器进程来通知渲染进程数据准备完毕你可以接收啦2 渲染进程收到通知会和网络进程间建立一条传输数据的“管道”3 接下来通过这条“管道”网络进程和渲染进程完成交接然后渲染进程会发送给浏览器进程一个“确认接收到响应数据”的消息4浏览器进程收到渲染进程发来的确认消息后会更新浏览器页面状态包括安全状态、地址栏的url、前进后退的历史状态、更新web页面这部分之后要着重学习整理下然后就可以开始渲染了但是进入渲染这个阶段不代表渲染是一下就完成的还要很多渲染前的必备的事情要做。下面继续细说渲染过程。回答到这里大致清晰的流程已经出来了如果不深入渲染过程记住后面是渲染过程就OK了。五 渲染1 DOM树的构建解析HTML是在渲染进程的主线程进行说明渲染引擎内有一个叫HTML解析器的模块该模块负责将HTML字节流转换为对应的DOM结构1词法分析HTML字节流首先通过分词器以词法分析的方式被转换为一个个TokenToken包括Tag Token和文本Token其中Tag Token包括StartTag Token和EndTag Token说明HTML解析器维护一个Token栈的结构该栈用于计算DOM中各节点间的父子关系2通过分词器后转换出来的Token经过以下处理生成DOM节点i. 如果该Token是一个StartTag Token那么将其压入栈中同时HTML为该Token创建一个DOM节点并将该节点加入到DOM树中ii. 如果该Token是一个文本Token则不需入栈同时HTML为其创建DOM节点并加入DOM树此时该文本节点的父节点即当前栈顶Token所对应的节点iii. 如果该Token是一个EndTag Token则检查当前栈顶Token是否是与其对应的StartTag Token是则将栈顶StartTag Token弹出到此表明一个标签解析完成比如div/div词法分析和DOM节点生成就是这么不断进行下去并且是同步进行的直到所有的HTML字节流都被解析完成此时DOM树也就构建好了。这里要注意这个HTML解析不是等到渲染进程接收完所有的HTML字节流也就是网络进程传输给渲染进程的响应数据才开始的而是网络进程传多少渲染进程接收到多少HTML也就解析多少这些步骤实际上都是同时进行的。2 CSSOM和渲染树DOM树构建好还不能直接渲染因为DOM节点对应的样式还没有加进来前提是有CSS样式。HTML解析过程中碰到CSS样式会去下载然后解析得到CSSOM。下载CSS不阻塞HTML解析但是解析“可能”阻塞。这样理解“可能”阻塞link标签不会像同步script一样使 HTML Parser 主动暂停。浏览器遇到link后会立即通知网络线程下载 CSS然后继续解析后续 HTML因此通常说CSS 下载不阻塞 HTML 解析。CSS 文件下载完成后需要在渲染进程主线程上解析生成 CSSOM这个解析过程会短暂占用主线程因此在极端情况下可能与 HTML Parser 竞争主线程资源。但这与同步script的规范要求暂停 HTML 解析是不同的概念。此外为了保证 JavaScript 能获取正确的样式信息浏览器会在必要时等待 CSSOM 构建完成后再执行后续脚本所以常说 CSS 会阻塞 JavaScript而不是阻塞 HTML 解析。解析CSS也是在渲染进程的主线程进行构建好的DOM树和解析完的CSSOM会经历过滤样式计算的过程从 DOM 树和 CSSOM 树到渲染树Render Tree核心机制可以概括为遍历 DOM 树的可见节点并在 CSSOM 中匹配样式生成一个仅包含可见元素及其计算样式的树结构。TipsDOM树和渲染树并非一一对应一个 DOM 节点不一定只对应一个渲染树节点也可能不生成渲染树节点。比如display:none的节点在DOM树中但不在渲染树中伪元素::before/::after它们不在 DOM 树中但会出现在渲染树中。计算CSS样式大概分为3步这3步就不详细展开了因为比较复杂自己也不是很懂大概是下面这样1将CSS转换为浏览器的能够理解的结构稍微具体一点就是渲染引擎接收到CSS文本时会执行一个转换操作将CSS文本转换为浏览器可以理解的结构——styleSheets2转换样式表中的属性值使其标准化3计算出DOM树中每个节点的具体样式3 布局计算计算布局还是是在渲染进程的主线程进行计算各节点在页面中的具体位置也就是怎么排放这些DOM节点。步骤如下1拿着上一步生成的渲染树再加上视口尺寸即浏览器内容区的宽高由窗口大小决定开始进行计算。2确定尺寸、确定坐标3生成布局树4 绘制网上很多文章比较笼统即布局之后就是绘制1接下来就是对布局树进行分层生成图层树这里简单提一下图层树这又涉及CSS中“层叠上下文”的知识不展开了。通常情况下一个DOM节点对应一层但有的节点没有自己的图层则从属于其父节点的图层。分配规则满足以下两点其中之一的节点会被分配到一个图层i.拥有层叠上下文属性的元素;ii.需要剪裁的地方也会被创建为图层比如div中的一段文字文字占地尺寸超出了div尺寸那么这时候会发生剪裁会为文字创建一个新的图层2渲染引擎内部根据图层树中各个图层会进行绘制。关于绘制执行者渲染进程的主线程Main Thread。输入生成的图层树Layer Tree每个图层包含布局计算好的几何信息。过程主线程遍历每一个图层记录“绘制动作”的顺序。比如“先画背景色为白色 - 再画边框为 1px 黑色 - 再画文字‘Hello’位于 (10, 20) 处”。输出每个图层对应的绘制指令列表Paint Records / Display Lists。此时还没有生成任何像素图只是一堆纯文本形式的绘图指令。5 合成显示渲染引擎完成绘制工作后还要进行分块与光栅化最后是合成。然后显示到屏幕上。关于分块执行者合成线程Compositor Thread注意此时已经脱离了主线程这也是为什么滚动不卡顿的原因。输入绘制指令列表Display Lists和图层尺寸。过程合成线程发现一个图层可能非常大比如一张 5000px 长的长图如果一次性交给 GPU 去处理内存会爆掉。因此它会把图层切割成无数个固定大小的小瓦片Tiles通常为 256x256 或 512x512 像素。输出按网格切分好的瓦片坐标集合Tile Coordinates。关于光栅化执行者光栅化线程池Raster Thread Pool位于渲染进程内的多线程工作池。输入特定瓦片的绘制指令比如“画个红方块在坐标 0,0”和该瓦片的坐标。过程这是将向量指令转为栅格像素/位图的物理计算过程。GPU 或 CPU 将这些指令渲染成填充了 RGBA红绿蓝透明度颜色的像素点存入内存中的纹理Texture。输出存储在 GPU 内存或系统内存中的位图Bitmap / 纹理数据。至此页面的内容变成了计算机能识别的“图片帧”。关于合成执行者合成线程输入图层纹理Textures光栅化线程池产出的像素位图已存储在 GPU 内存中。图层属性Layer Properties每个图层的transform位移/旋转/缩放、opacity透明度、filter滤镜、clip裁剪边界以及滚动偏移量scrollTop。图层层级树Layer Tree明确哪个图层在上层z-index哪个在下层。视口信息Viewport当前屏幕的宽高和可见区域坐标用于裁剪。过程对输入数据进行“几何运算与堆叠”输出绘图指令包并提交给GPU进程最后因为最近做的一个项目没想到过了好久又要重新捡起这部分知识参考了很多文章后加上我个人的理解大概地解释了下只是“大概”因为这个问题涉及的知识实在是太多了以上应该也只是总结了一半要深入的代价是头秃先不说渲染这个过程有多繁琐光是所涉及操作系统中进程和线程相关的概念都需要好好整理一遍但是从输入url到页面渲染大致的流程参考以上具体步骤已经能解答大部分疑惑了