细细细!!! 输入URL到页面渲染的全过程

大家可以看一看先浏览器进程和线程的文章,在我之前的文章有写。

tab外面发生的一切事情都是由浏览器主进程决定,首先输入URL网址,其实是UI线程在处理我们的输入。

我们按下回车首先UI线程会判断我们输入的是一些搜索关键词还是一个URL地址,因为URL也可以搜索关键信息。

这时候主进程会去查看Service Worker中注册状态。service worker能够决定哪些数据缓存到本地,哪些数据需要重新获取。 service其实是跑在渲染进程中的js代码。假如遇到了注册过的请求,就会启动一个渲染进程来执行他的代码,进行渲染页面。

假如service worker未注册的话这时候UI线程通过IPC通信通知网络进程了,告诉他让他去请求网址。我们的 我们的网络进程首先会去检查一下HTTP的缓存。关于HTTP这方面可以看一下小编的文章HTTP , Websocket

  • 网络进程按顺序检查:
    1. 内存缓存(200 from memory cache)
    2. 磁盘缓存中的强缓存(200 from disk cache)
    3. 协商缓存验证(304 Not Modified)
js 复制代码
graph TD
    A[请求发起] --> B{内存缓存有效?}
    B -->|是| C[返回200 from memory]
    B -->|否| D{磁盘强缓存有效?}
    D -->|是| E[返回200 from disk]
    D -->|否| F{磁盘有验证信息?}
    F -->|是| G[发送条件请求]
    G --> H{服务器返回304?}
    H -->|是| I[更新缓存并返回304]
    H -->|否| J[返回新内容]
    F -->|否| K[正常网络请求]

如果没有缓存,这时候就要开始我们的网络请求了。

DNS解析

这时候网络进程首先会进行DNS解析

DNS也有多级缓存机制。

x.com 没有缓存时的完整流程:

  1. 浏览器缓存未命中 →
  2. 检查hosts文件无记录 →
  3. 系统缓存未命中 →
  4. 查询路由器缓存未命中 →
  5. 向本地DNS服务器发起递归查询

详解:

首先他会去查询我们浏览器中的DNS缓存。Chrome中DNS缓存是有一个大概1MB的区域。他是60s清除一次。当我们关闭浏览器会清除缓存或者打开隐私模式不会缓存。

假如我们超出60s或没查询到信息,则会去查看我们的系统缓存。 首先会去查看本地的host文件。这是一个静态文件,能够让用户自己配置DNS解析。

还没查询到,这时候就会去查看操作系统缓存,这里记录了所有浏览器的查询记录,所有浏览器共享(每个DNS返回有个TTL,最大10min更新)。

假如还是没查询到,这时候就会去向路由发送请求,家用路由器同样会缓存DNS,通常为10-30min。

假如还是没查询到,会向域名服务器发起请求来解析。首先会去查询本地域名服务器(本地运营商提供:电信,移动)。如果还没查询到,本地域名服务器会向根服务器请求,他会返回顶级域名服务器的地址,接着顶级域名服务器会返回权威域名服务器的地址,最终在权威域名服务器中查询到DNS纪录。

  • 递归查询:客户端只发一次请求,DNS服务器负责全部查询工作

  • 迭代查询:本地DNS服务器向更高级DNS服务器发起的是迭代查询,即如果对方不知道答案,会返回"我不知道,但你可以去问这个服务器"

TCP 三次握手

接着就是建立TCP连接的过程,这里详细复习一下

刚开始客户端处于closed(关闭)状态,服务器处于listen(监听)状态。

第一次握手: 客户端发送一个SYN报文给服务器,并指明客户端的初始化序列号为SN。此时客户端处于SYN_SENT(同步发送)状态。

第二次握手:服务器收到了客户端的SYN报文的SYN报文应答,同时指定服务器的初始化序列为ISN,同时把 客户端的ISN+1作为ACK的值返回。此时服务器处于SYN_REVD(同步接收)状态。

第三次握手客户端收到服务器的SYN之后,一样将服务器的ISN序列+1当成ACK的值进行返回此时客户端处于establised状态。

接着服务器收到后,也处于establised(建立)状态,连接建立。

接收响应

网络进程在接收到HTTP的主体流之后,相应类型一般可以通过HTTP请求头的content-Type进行确定。但是有时候他是缺失或者错误的,浏览器解析失败,这时候浏览器就要 进行MIME类型嗅探来判断主体是什么媒体类型。(这时候会对响应数据的前几个字节(魔数)进行判断,以进行资源类型的检查。等等)

  • 如果获取的是一个HTML文件,还会对内容做一些检查。 会通过IPC交给渲染进程进行渲染,(在UI进程进行)。
  • 如果是一个压缩文件或者是其他文件类型,则会交给下载管理器进行下载。

渲染进程接收到提交之后,导航栏开始更新,tab的会话历史也会更新,用户能够回退进行恢复当前会话。这时候,渲染进程开始工作了。

渲染进程发生的事

1.构建DOM树 CSSOM树

我们的GUI渲染线程会去解析负责HTML文档的解析,生成DOM树。它具有很大的容错能力,例如标签没闭合也不会报错。

当遇到了CSS样式,便会跟DOM树同步构建CSSOM树。(因为我们的样式复杂,会有优先级,继承)。

解析的途中可能会碰到一些例如图片,script,css这种需要下载的样式。他会逐步进行下载。不过现在的浏览器具备预加载扫描器。 可以同时的发起多个请求。并将需要的资源通过ICP告诉网络进程。

  • 注意: 浏览器遇到script标签就会阻塞DOM树的构建,暂停HTML的解析。因为我们的js脚本可能更改我们的DOM树。等到js下载并且执行完成之后才会继续构建DOM树。 我们可以通过给script标签加上一个async(异步下载,下载后立即执行) 或者defer(异步下载,延迟到DomContentLoaded前执行)属性来使得script脚本进行异步加载。也可以使用preload属性指定当前页面的关键资源,优先加载。
  • 但是我们的CSS样式的下载不会阻塞DOM树的构建,但是他会阻塞render树的合成过程,因为需要CSS样式。

样式计算 Style caculation

当DOM树和CSSOM树都构建完成,我们便会开始计算每个节点的最终样式(样式计算)。即使每个节点没有设置样式,仍然DOM节点都会有样式,因为每个浏览器有自己的默认样式表,这也就是为什么有时候我们的body会有默认的margin,每个浏览器还不同。

然后构建起最终的渲染树(会过滤掉不可见的节点 display:none)

布局 layout

我们已经有了具体的几何图形,但是你想一想,假设我喊你画一个圆,一个长方形,你知道怎么画吗?放在哪儿?画多大? 浏览器会根据文档流的规则给页面进行布局。生成一颗布局树,包括每个元素的具体xy坐标,以及盒子大小,层级关系的具体信息。

绘制 分层

知道了具体的位置,还是不能清楚怎么画,因为你想,我们绘画的图形是有遮挡的,会有顺序。假如设置了z-index,我们该先画谁后画谁呢?绘画这个步骤,会根据之前生成的layout布局树,生成对应的绘画指令。然后发送给GPU。(这里会生成一个RenderLayerTree 用来处理绘制顺序,堆叠层次)

分层式浏览器出于性能优化,他在某些特定的情况会对页面进行分层。他跟z-index不一样,z-index是影响的堆叠上下文,也就是绘制的顺序。分层决定的是渲染的一个处理方式。

当使用一些特定的css属性的时候会触发新图层的创建,例如translate3D,translateZ, will-change: transform/opacity/filter , 固定定位,vedio标签,opacity小于1且有动画。

采用分层,这样我们的一些图像分到了独立层中,不必每次微小改变就引起原来层的重绘重排,只需要最后进行图层合成即可。(这里分层之后会生成一个GraphicsLayer树 合成层树)

当使用了translatez后,会创建图层。浏览器会将元素渲染成位图(光栅化)。这个位图被上传到GPU内存成为纹理。GPU就可以直接对这个纹理进行移动,缩放。

光栅化

  1. 接收绘制指令:浏览器生成一系列绘制命令,如"画矩形"、"填充文本"、"应用渐变"等
  1. 几何处理:
  • 计算每个形状的精确边界
  • 确定形状之间的重叠区域
  • 处理剪切区域(clipping regions)
  1. 三角形分解:
  • 复杂形状被分解成三角形网格
  • 这是因为三角形是图形硬件能高效处理的基本单位
  1. 像素映射:
  • 确定哪些像素落在几何形状内部
  • 使用采样算法确定边缘像素是否被覆盖
  1. 纹理映射与着色:
  • 应用颜色、渐变、图案等
  • 计算每个像素的最终颜色值
  1. 抗锯齿处理:
  • 处理边缘像素,使线条和曲线看起来更平滑
  • 常用技术包括MSAA(多重采样抗锯齿)

合成

页面会在合成线程中合并成一个页面。各个页面已经光栅化了,浏览器只需要根据合成层次树合成一个新的帧来展示滚动后的效果。页面的动画效果也是类似的。将页面上的层进行移动构建出一个新的帧即可。

相关推荐
牛马baby9 小时前
Java高频面试之并发编程-01
java·开发语言·面试
拉不动的猪10 小时前
刷刷题48 (setState常规问答)
前端·react.js·面试
uhakadotcom11 小时前
Thrift2: HBase 多语言访问的利器
后端·面试·github
Moment11 小时前
一份没有项目展示的简历,是怎样在面试里输掉的?开源项目或许是你的救命稻草 😭😭😭
前端·后端·面试
努力的搬砖人.12 小时前
Vue 2 和 Vue 3 有什么区别
前端·vue.js·经验分享·面试
uhakadotcom12 小时前
轻松掌握XXL-JOB:分布式任务调度的利器
后端·面试·github
失乐园14 小时前
解密万亿级消息背后:RocketMQ高吞吐量核心机制解剖
java·后端·面试
yzzzz15 小时前
面试官:聊聊数组扁平化
javascript·面试
Java水解15 小时前
Java面试必问到的10道面试题
java·面试
张子栋15 小时前
面试官:说下Cookie和Session的关系和区别,以及Token是什么?
面试