输入url后回车发生了什么(持续更新)

2023-12-25 18:41:16
在大多数情况下,浏览器被认为是单线程的。也就是说,他们从头到尾执行一项任务,然后再开始另一项任务。为了实现流畅的交互,开发人员的目标是确保高性能的站点交互,从平滑滚动到触摸响应。渲染时间是关键,确保主线程可以完成我们交给它的所有工作,并且仍然始终可以处理用户交互。通过了解浏览器的单线程性质并在可能和适当的情况下最大程度地减少主线程的职责,以确保渲染顺利并且对交互的响应立即响应,可以提高?Web?性能。

导航:DNS解析

导航是加载网页的第一步。每当用户通过在地址栏中输入?URL、单击链接、提交表单以及其他操作来请求页面时,就会发生这种情况。

Web?性能的目标之一是最大限度地减少完成导航所需的时间。在理想条件下,这通常不会花费太长时间,但延迟和带宽是可能导致延迟的敌人。

DNS查询

导航到网页的第一步是查找该页面的资源所在的位置。如果您导航到https://example.com,HTML?页面位于?IP?地址为?的服务器上93.184.216.34。如果您从未访问过此站点,则必须进行?DNS?查找。

您的浏览器请求?DNS?查找,该查找最终由名称服务器进行处理,而名称服务器又以?IP?地址进行响应。在此初始请求之后,IP?可能会被缓存一段时间,这通过从缓存中检索?IP?地址而不是再次联系名称服务器来加速后续请求。

对于页面加载,通常只需为每个主机名执行一次?DNS?查找。但是,必须对请求页面引用的每个唯一主机名进行?DNS?查找。如果您的字体、图像、脚本、广告和指标都具有不同的主机名,则必须对每一个进行?DNS?查找。

这可能会影响性能,尤其是在移动网络上。当用户使用移动网络时,每次?DNS?查找都必须从手机到手机信号塔才能到达权威?DNS?服务器。电话、手机信号塔和名称服务器之间的距离会显着增加延迟。

握手:TCP连接

一旦知道?IP?地址,浏览器就会通过TCP?三向握手建立与服务器的连接。这种机制的设计使得尝试通信的两个实体(在本例中为浏览器和?Web?服务器)可以在传输数据之前协商网络?TCP?套接字连接的参数(通常通过HTTPS)。

TCP?的三向握手技术通常称为“SYN-SYN-ACK”,或更准确地说是?SYN、SYN-ACK、ACK,因为?TCP?传输三个消息来协商并启动两台计算机之间的?TCP?会话。是的,这意味着每个服务器之间还要来回三个消息,并且请求尚未发出。

TLS?协商

对于通过?HTTPS?建立的安全连接,需要再次“握手”。此握手(或者更确切地说TLS协商)确定将使用哪个密码来加密通信、验证服务器并在开始实际数据传输之前建立安全连接。在实际发送内容请求之前,这还需要与服务器进行五次以上的往返。

虽然确保连接安全会增加页面加载时间,但安全连接值得付出延迟代价,因为浏览器和?Web?服务器之间传输的数据无法被第三方解密。

经过八次与服务器的往返之后,浏览器终于??能够发出请求。

发送:HTTP请求

一旦我们与?Web?服务器建立了连接,浏览器就会代表用户发送初始HTTP GET请求,对于网站来说,该请求通常是?HTML?文件。

回复:HTTP相应

服务器收到请求后,会回复相关的响应头和?HTML?内容。

该初始请求的响应包含接收到的数据的第一个字节。第一个字节的时间(TTFB)?是用户发出请求(例如通过单击链接)到收到第一个?HTML?数据包之间的时间。第一个内容块通常是?14KB?的数据。

在我们上面的例子中,请求肯定小于14KB,但是直到浏览器在解析过程中遇到链接时才会请求链接的资源,如下所述。

拥塞控制/TCP慢启动

TCP?数据包在传输过程中被分成段。由于?TCP?保证数据包的顺序,因此服务器在发送一定数量的数据段后必须收到客户端以?ACK?数据包形式的确认。

如果服务器在每个数据段后等待?ACK,那么即使在低负载网络的情况下,也会导致来自客户端的频繁?ACK?并可能增加传输时间。

另一方面,一次发送太多报文段可能会导致这样的问题:在繁忙的网络中,客户端将无法接收报文段,并且会在很长一段时间内保持以?ACK?进行响应,而服务器则必须保持重新发送片段。

为了平衡传输的报文段数量,采用TCP慢启动算法逐渐增加传输的数据量,直到可以确定最大网络带宽,并在网络负载较高的情况下减少传输的数据量。

传输的报文段数由拥塞窗口(CWND)的值控制,可以初始化为1、2、4或10个MSS(以太网协议上的MSS为1500字节)。该值是要发送的字节数,客户端收到该字节后必须发送?ACK。

如果收到?ACK,则?CWND?值将加倍,因此服务器下次将能够发送更多数据段。如果没有收到?ACK,则?CWND?值将减半。因此,该机制在发送太多分段和发送太少分段之间实现了平衡。

解析:HTML渲染

一旦浏览器接收到第一块数据,它就可以开始解析接收到的信息。解析是浏览器将通过网络接收到的数据转换为DOM和CSSOM?的步骤,渲染器使用它们将页面绘制到屏幕上。

DOM?是浏览器标记的内部表示。DOM?也是公开的,可以通过?JavaScript?中的各种?API?进行操作。

即使请求页面的?HTML?大于初始?14KB?数据包,浏览器也会开始解析并尝试根据其拥有的数据呈现体验。这就是为什么在前?14KB?中包含浏览器开始渲染页面所需的所有内容,或者至少包含页面模板(首次渲染所需的?CSS?和?HTML)对于?Web?性能优化非常重要的原因。但在将任何内容呈现到屏幕上之前,必须解析?HTML、CSS?和?JavaScript。

构建?DOM?树

我们描述了关键渲染路径中的五个步骤。

第一步是处理?HTML?标记并构建?DOM?树。HTML?解析涉及标记化和树构建。HTML?标记包括开始和结束标记,以及属性名称和值。如果文档格式良好,则解析它会直接且更快。解析器将标记化输入解析到文档中,构建文档树。

DOM?树描述了文档的内容。该<html>元素是文档树的第一个元素和根节点。树反映了不同元素之间的关系和层次结构。嵌套在其他元素中的元素是子节点。DOM?节点的数量越多,构建?DOM?树所需的时间就越长。

当解析器找到非阻塞资源(例如图像)时,浏览器将请求这些资源并继续解析。当遇到?CSS?文件时,解析可以继续,但<script>元素(尤其是那些没有asyncordefer属性的元素)会阻止渲染,并暂停?HTML?的解析。尽管浏览器的预加载扫描程序加速了这一过程,但过多的脚本仍然可能是一个重要的瓶颈。

预装扫描仪

当浏览器构建?DOM?树时,这个过程占用主线程。发生这种情况时,预加载扫描器将解析可用内容并请求高优先级资源,例如?CSS、JavaScript?和?Web?字体。感谢预加载扫描器,我们不必等到解析器找到对外部资源的引用来请求它。它将在后台检索资源,以便当主?HTML?解析器到达所请求的资源时,它们可能已经在运行或已被下载。预加载扫描仪提供的优化可减少阻塞。

<link rel="stylesheet" href="styles.css" />
<script src="myscript.js" async></script>
<img src="myimage.jpg" alt="image?description" />
<script src="anotherscript.js" async></script>

在此示例中,当主线程解析?HTML?和?CSS?时,预加载扫描器将找到脚本和图像,并开始下载它们。为了确保脚本不会阻止进程,请添加该async属性,defer如果?JavaScript?解析和执行顺序很重要,则添加该属性。

等待获取?CSS?不会阻止?HTML?解析或下载,但它会阻止?JavaScript,因为?JavaScript?经常用于查询?CSS?属性对元素的影响。

构建?CSSOM?树

关键渲染路径的第二步是处理?CSS?并构建?CSSOM?树。CSS?对象模型类似于?DOM。DOM?和?CSSOM?都是树。它们是独立的数据结构。浏览器将?CSS?规则转换为它可以理解和使用的样式映射。浏览器遍历?CSS?中的每个规则集,根据?CSS?选择器创建具有父、子和兄弟关系的节点树。

与?HTML?一样,浏览器需要将接收到的?CSS?规则转换为它可以使用的内容。因此,它重复?HTML?到对象的过程,但对于?CSS。

CSSOM?树包含来自用户代理样式表的样式。浏览器从适用于节点的最通用规则开始,并通过应用更具体的规则递归地细化计算的样式。换句话说,它级联了属性值。

构建?CSSOM?非常非常快,并且在当前的开发人员工具中不会以独特的颜色显示。相反,开发人员工具中的“重新计算样式”显示了解析?CSS、构建?CSSOM?树和递归计算计算样式所需的总时间。在?Web?性能优化方面,有一些唾手可得的成果,因为创建?CSSOM?的总时间通常小于一次?DNS?查找所需的时间。

其他工艺

JavaScript?编译

在解析?CSS?并创建?CSSOM?的同时,正在下载其他资源,包括?JavaScript?文件(感谢预加载扫描器)。JavaScript?被解析、编译和解释。脚本被解析为抽象语法树。一些浏览器引擎采用抽象语法树并将它们传递给编译器,输出字节码。这称为?JavaScript?编译。大部分代码在主线程上解释,但也有例外,例如在Web?Workers中运行的代码。

构建可访问性树

浏览器还构建辅助设备用来解析和解释内容的可访问性树。可访问性对象模型?(AOM)?就像?DOM?的语义版本。当?DOM?更新时,浏览器也会更新可访问性树。辅助技术本身无法修改辅助功能树。

在构建?AOM?之前,屏幕阅读器无法访问内容。

渲染

渲染步骤包括样式、布局、绘制,在某些情况下还包括合成。在解析步骤中创建的?CSSOM?和?DOM?树被组合成渲染树,然后使用该渲染树计算每个可见元素的布局,然后将其绘制到屏幕上。在某些情况下,内容可以提升到其自己的层并进行合成,通过在?GPU?而不是?CPU?上绘制部分屏幕来提高性能,从而释放主线程。

风格

关键渲染路径的第三步是将?DOM?和?CSSOM?组合成渲染树。计算样式树或渲染树的构造从?DOM?树的根开始,遍历每个可见节点。

不会显示的元素(例如<head>元素及其子元素以及带有?的任何节点display:?none(例如script?{?display:?none;?}您在用户代理样式表中找到的?))不会包含在渲染树中,因为它们不会出现在渲染输出中。应用的节点visibility:?hidden包含在渲染树中,因为它们确实占用空间。由于我们没有给出任何指令来覆盖用户代理默认值,因此script上面代码示例中的节点将不会包含在渲染树中。

每个可见节点都应用了其?CSSOM?规则。渲染树保存所有具有内容和计算样式的可见节点?-?将所有相关样式与?DOM?树中的每个可见节点进行匹配,并根据?CSS?级联确定每个节点的计算样式。

布局

关键渲染路径的第四步是在渲染树上运行布局以计算每个节点的几何形状。布局是确定渲染树中所有节点的尺寸和位置,以及确定页面上每个对象的大小和位置的过程。回流是页面或整个文档的任何部分的任何后续尺寸和位置确定。

一旦构建了渲染树,布局就开始了。渲染树识别显示哪些节点(即使不可见)及其计算样式,但不识别每个节点的尺寸或位置。为了确定每个对象的确切大小和位置,浏览器从渲染树的根开始并遍历它。

在网页上,几乎所有东西都是一个盒子。不同的设备和不同的桌面首选项意味着无限数量的不同视口大小。在此阶段,考虑到视口大小,浏览器确定屏幕上所有不同框的大小。以视口的大小为基础,布局通常从主体开始,布置所有主体后代的尺寸,以及每个元素的盒模型属性,为不知道尺寸的替换元素提供占位符空间,例如作为我们的形象。

第一次确定每个节点的大小和位置称为布局。随后的重新计算称为回流。在我们的示例中,假设初始布局发生在返回图像之前。由于我们没有声明图像的尺寸,因此一旦知道图像尺寸就会进行回流。

重绘

关键渲染路径的最后一步是将各个节点绘制到屏幕上,第一次出现称为第一个有意义的绘制。在绘画或光栅化阶段,浏览器将布局阶段计算的每个框转换为屏幕上的实际像素。绘画涉及将元素的每个视觉部分绘制到屏幕上,包括文本、颜色、边框、阴影以及按钮和图像等替换元素。浏览器需要非常快地完成此操作。

为了确保平滑的滚动和动画,所有占用主线程的事情,包括计算样式、回流和绘制,都必须让浏览器在?16.67?毫秒以内完成。在?2048?x?1536?分辨率下,iPad?有超过?3,145,000?个像素可绘制到屏幕上。这是大量必须快速绘制的像素。为了确保重新绘制比初始绘制更快,屏幕上的绘图通常分为几个层。如果发生这种情况,则需要进行合成。

绘画可以将布局树中的元素分解为图层。将内容提升到?GPU?上的图层(而不是?CPU?上的主线程)可提高绘制和重绘制性能。有一些特定的属性和元素可以实例化图层,包括<video>和<canvas>,以及任何具有?CSS?属性opacity、?3D?transform、will-change和其他一些元素。这些节点将与其后代一起绘制到它们自己的层上,除非后代由于上述一个(或多个)原因需要自己的层。

层确实可以提高性能,但在内存管理方面成本高昂,因此不应过度使用作为?Web?性能优化策略的一部分。

合成

当文档的各个部分绘制在不同的层中且彼此重叠时,需要进行合成以确保它们以正确的顺序绘制到屏幕上并正确呈现内容。

当页面继续加载资源时,可能会发生重排(回想一下我们迟到的示例图像)。回流引发了重新绘制和重新合成。如果我们定义了图像的尺寸,则不需要回流,并且只有需要重新绘制的图层才会被重新绘制,并在必要时进行合成。但我们没有包括图像尺寸!从服务器获取图像后,渲染过程将返回到布局步骤并从那里重新开始。

互动性

一旦主线程完成页面绘制,您可能会认为我们已经“准备就绪”。情况不一定如此。如果加载包含?JavaScript,则该加载已正确延迟,并且仅在onload事件触发后执行,则主线程可能很忙,并且无法用于滚动、触摸和其他交互。

交互时间(TTI)?是衡量从导致?DNS?查找和?TCP?连接的第一个请求到页面交互所需时间的时间?—?交互是页面响应第一次内容绘制之后的时间点50?毫秒内的用户交互。如果主线程被占用解析、编译和执行?JavaScript,则它不可用,因此无法及时(小于?50?毫秒)响应用户交互。

在我们的示例中,也许图像加载得很快,但anotherscript.js文件可能有?2MB,而我们用户的网络连接速度很慢。在这种情况下,用户会非常快地看到页面,但在下载、解析和执行脚本之前无法滚动而不出现卡顿。这不是一个好的用户体验。避免占用主线程。

?

文章来源:https://blog.csdn.net/weixin_49307011/article/details/135203223
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。