自总结从输入url到页面渲染到底经历了啥(下)

简介: 自总结从输入url到页面渲染到底经历了啥

浏览器缓存


如果缓存生效,那么将不会向服务器请求数据,直接使用缓存,降低服务器的压力。


强缓存


  • expires: GMT格式时间


  • cache-control


网络异常,图片无法展示
|


no-store, no-cache, must-revalidate的区别:


网络异常,图片无法展示
|


协商缓存


  • etag / if-none-match


  • modified-since / if-modified-since 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。


通过如果使用缓存,将返回304 Not Modified。 它用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成“重定向已到缓存的文件”(即“缓存重定向”)。


处理响应请求,服务器渲染HTML文件


按照渲染的时间顺序,流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。


  • 开始每个子阶段都有其输入的内容;


  • 然后每个子阶段有其处理过程;


  • 最终每个子阶段会生成输出内容。


构建 DOM 树


为什么要构建 DOM 树呢?这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。


DOM 和 HTML 内容几乎是一样的,但是和 HTML 不同的是,DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容。


样式计算(Recalculate Style)


把 CSS 转换为浏览器能够理解的结构


和 HTML 文件一样,浏览器也是无法直接理解这些纯文本的 CSS 样式,所以当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。可以通过document.styleSheets查看结构。


转换样式表中的属性值,使其标准化


现有的 CSS 文本转化为浏览器可以理解的结构了,那么接下来就要对其进行属性值的标准化操作。


CSS 文本中有很多属性值,如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。


计算出 DOM 树中每个节点的具体样式.


样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承和层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。


这就涉及到 CSS 的继承规则和层叠规则了。


  • 首先是 CSS 继承。CSS 继承就是每个 DOM 节点都包含有父节点的样式。


  • css层叠。层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称“层叠样式表”正是强调了这一点。


布局阶段


现在,我们有 DOM 树和 DOM 树中元素的样式,但这还不足以显示页面,因为我们还不知道 DOM 元素的几何位置信息。那么接下来就需要计算出 DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局。


创建布局树


你可能注意到了 DOM 树还含有很多不可见的元素,比如 head 标签,还有使用了 display:none 属性的元素。所以在显示之前,我们还要额外地构建一棵只包含可见元素布局树


网络异常,图片无法展示
|


布局计算


现在我们有了一棵完整的布局树。那么接下来,就要计算布局树节点的坐标位置了


在执行布局操作的时候,会把布局运算的结果重新写回布局树中,所以布局树既是输入内容也是输出内容,这是布局阶段一个不合理的地方,因为在布局阶段并没有清晰地将输入内容和输出内容区分开来。


分层


现在我们有了布局树,而且每个元素的具体位置信息都计算出来了,那么接下来是不是就要开始着手绘制页面了?不可以。


因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。


网络异常,图片无法展示
|


通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。


元素应该满足什么样的条件,才会创建一个新的图层呢?


  • 第一点,拥有层叠上下文属性的元素会被提升为单独的一层。


页面是个二维平面,但是层叠上下文能够让 HTML 元素具有三维概念,这些 HTML 元素按照自身属性的优先级分布在垂直于这个二维平面的 z 轴上。即z-index。


  • 第二点,需要剪裁(clip)的地方也会被创建为图层。剪切这个是广义上的。比如多余的文字来控制怎么展示。即overflow属性。


图层绘制


在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制。


渲染引擎实现图层的绘制会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。


栅格化(raster)操作


绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。


当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程。

有可能一个图层很大,一个屏幕展示不下,那么在未看见的部分如果也渲染了,那么就产生很大的开销。基于这个原因。合成线程会将图层划分为图块。 这些图块的大小通常是 256x256 或者 512x512。


然后合成线程会按照视口附近的图块来优先生成位图, 实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。


网络异常,图片无法展示
|


通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。


网络异常,图片无法展示
|


合成和显示


光栅化就是按照绘制列表中的指令生成图片。每一个图层都对应一张图片,合成线程有了这些图片之后,会将这些图片合成为“一张”图片,并最终将生成的图片发送到后缓冲区。这就是一个大致的分层、合成流程。


一旦所有图块都被光栅化合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。


浏览器进程里面有一个叫 viz 的组件用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

到这里,经过这一系列的阶段,编写好的 HTML、CSS、JavaScript 等文件,经过浏览器就会显示出漂亮的页面了。


需要重点关注的是,合成操作是在合成线程上完成的,这也就意味着在执行合成操作时,是不会影响到主线程执行的。这就是为什么经常主线程卡住了,但是 CSS 动画依然能执行的原因。


总结


  1. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。


  1. 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。


  1. 创建布局树,并计算元素的布局信息。


  1. 对布局树进行分层,并生成分层树。


  1. 为每个图层生成绘制列表,并将其提交到合成线程。


  1. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。


  1. 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。


  1. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。


断开连接,TCP的四次挥手


网络异常,图片无法展示
|


为什么建立连接是三次握手,而关闭连接却是四次挥手呢


这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。


而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,自己也未必全部数据都发送给对方了,所以自己可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,自己的ACK和FIN一般都会分开发送。


为什么客户端发送ACK之后不直接关闭,而是要等一阵子才关闭


客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。如果不等待,客户端直接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,若客户端的端口此时刚好被新的应用占用,那么就接收到了无用数据包,造成数据包混乱。


为什么TIME_WAIT状态需要经过2MSL(最大报文生存时间)才能返回到CLOSE状态


理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。


  • 为了确保最后一个确认报文能够到达,未到达,则重发。


  • 为了使服务器发送的数据都在网络上消失,确保下一个连接不会出现旧连接的报文。


参考文章


极客时间 罗剑锋(Chrono)老师的 透视HTTP协议


极客时间 李兵老师的 浏览器工作原理与实践


从输入URL开始建立前端知识体系


从输入 URL 到页面展示到底发生了什么?看完吊打面试官!文章


面试官问我TCP三次握手和四次挥手,我真的是文章


面试官,不要再问我三次握手和四次挥手


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
22天前
|
存储 缓存 网络协议
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点,GET、POST的区别,Cookie与Session
计算机网络常见面试题(二):浏览器中输入URL返回页面过程、HTTP协议特点、状态码、报文格式,GET、POST的区别,DNS的解析过程、数字证书、Cookie与Session,对称加密和非对称加密
|
24天前
|
域名解析 缓存 网络协议
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
浏览器中输入URL返回页面过程(超级详细)、DNS域名解析服务,TCP三次握手、四次挥手
|
3月前
|
网络协议 前端开发 JavaScript
浏览器加载网页的幕后之旅:从URL到页面展示详解
【8月更文挑战第31天】当在浏览器地址栏输入URL并回车后,一系列复杂过程随即启动,包括DNS解析、TCP连接建立、HTTP请求发送、服务器请求处理及响应返回,最后是浏览器页面渲染。这一流程涉及网络通信、服务器处理和客户端渲染等多个环节。通过示例代码,本文详细解释了每个步骤,帮助读者深入理解Web应用程序的工作机制,从而在开发过程中作出更优决策。
65 5
|
3月前
|
缓存 前端开发 JavaScript
输入URL到页面渲染的全过程
输入URL到页面渲染的全过程
34 1
|
3月前
|
JavaScript Linux 应用服务中间件
【Azure 应用服务】FTP 部署 Vue 生成的静态文件至 Linux App Service 后,访问App Service URL依旧显示Azure默认页面问题
【Azure 应用服务】FTP 部署 Vue 生成的静态文件至 Linux App Service 后,访问App Service URL依旧显示Azure默认页面问题
|
3月前
|
API UED 开发者
Vaadin路由魔法:导航之舟,带你穿越页面迷宫!驾驭神奇URL,解锁无限可能!
【8月更文挑战第31天】Vaadin是一款现代Java Web开发框架,其路由机制结合前后端路由,确保流畅的用户体验和高效服务器资源利用。通过`@Route`注解和`Router`类,开发者可以轻松定义和管理页面路径。例如,`@Route("home")`可指定视图路径,而参数化路由如`@Route("user/:userId")`则允许URL传参。此外,Vaadin还提供了丰富的导航API和自定义路由事件监听器,助力开发者构建结构清晰且体验优秀的Web应用。
48 0
|
3月前
|
缓存 网络协议 JavaScript
面试常考题:输入url到页面渲染发生了什么?(前半段)
面试常考题:输入url到页面渲染发生了什么?(前半段)
|
3月前
|
JavaScript 前端开发 网络协议
面试常考题: 输入url到页面渲染发生了什么(后半段)
面试常考题: 输入url到页面渲染发生了什么(后半段)
|
5月前
|
缓存 网络协议 前端开发
【高频】从输入URL到页面展示到底发生了什么?
【高频】从输入URL到页面展示到底发生了什么?
|
5月前
|
Web App开发 移动开发 安全
如何做到修改 url 参数页面不刷新
如何做到修改 url 参数页面不刷新