浏览器输入url,按下回车之后发生了什么

228 阅读27分钟

一道经典的面试题,可以把浏览器组织架构、网络通信、浏览器渲染等知识点整合起来。今天来总结一下,不足之处请提出宝贵意见。

一. 处理输入

当用户开始在地址栏中输入内容时,浏览器中的UI线程 询问的第一件事是:“这是搜索查询还是URL? ”在Chrome中,地址栏也是一个搜索输入的地方,因此UI线程需要解析并决定是将你输入的内容发送到搜索引擎,还是发送到你请求的站点。 image.png 如果输入的是搜索内容,则使用默认的搜索引擎进行搜索。默认的搜索引擎可以通过地址栏左侧的图标看出,比如下面就是google,切换其他引擎的话可以到浏览器配置中修改。 image.png
如果是URL,则解析URL,获取网页资源。

二. 检查本地缓存

浏览器会首先查找要请求的资源是否命中本地缓存。本地缓存就是之前请求过的相同资源,保存在本地。
对于已经命中的缓存资源,需要判断其是否依然可用。
本地缓存有多种,如果命中的是Service Worker缓存的话,缓存逻辑由页面自身对Service Worker的API调用方式控制;如果是其他类型缓存,比如内存缓存、磁盘缓存是否继续使用,需要根据是这些缓存资源获取到的时候的两个响应头判断:

  1. Expire:
    缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。是HTTP1.0的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
  2. Cache-Control:
    缓存控制头,通过一系列的指令来具体指定本地缓存的策略。比如,
    • Cache-Control: max-age=300, 缓存资源在请求发送后300秒内有效,超过这个时间就会过期;
    • Cache-control: private,只能由用户缓存,代理服务器不能缓存;
    • .....更多配置可以查看 MDN

如果本地缓存命中且可用,就不进行网络请求,直接跳到渲染步骤;
如果本地缓存命中了但是缓存不生效,可以请求服务端进行协商缓存的判断,服务端判断可用,会给响应体赋304状态码,这样本地缓存依然可用;
如果没命中任何缓存,就继续请求资源。浏览器中的UI线程会通知网络线程去获取网页资源,并控制 tab 上的 spinner(也就是 tab 左边的刷新按钮)开始旋转,表示正在加载中。

image.png 这时,网络线程会执行适当的协议,例如DNS解析,并为请求建立TCP连接,如果是https地址的话需要建立TLS连接。

三. DNS查找

DNS,就是Domain Name System的缩写,翻译过来就是域名系统,是互联网上作为域名IP地址相互映射的一个分布式数据库。它将简单明了的域名翻译成可由计算机识别的IP地址,使用户可以更快速便捷地访问互联。

什么是域名?

域名是由一串用点分隔的字符组成的互联网上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位。 域名可以说是一个IP地址的代称,目的是为了便于记忆后者。
域名的结构由标号序列组成,各标号之间用点隔开。类似于这样:“….三级域名.二级域名.顶级域名” 。各级域名由其上一级的域名管理机构管理,而最高级的顶级域名则由 ICANN(互联网名称与数字地址分配机构)进行管理。
image.png

DNS查询步骤

域名解析一般采用递归查询的方式进行。一个完整的域名解析过程如下:

  1. 首先到DNS缓存中有没有对应的,找到就省事了。
    1.1. 查看浏览器缓存
    当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的 IP 地址(若曾经访问过该域名且没有清空缓存便存在)。
    1.2. 查看系统缓存
    当浏览器缓存中无域名对应 IP 则会自动检查用户计算机系统 Hosts 文件 DNS 缓存是否有该域名对应 IP。
    1.3. 查看路由器缓存
    当浏览器及系统缓存中均无域名对应 IP 则进入路由器缓存中检查,以上三步均为客户端的 DNS 缓存。
    1.4. 查看ISP DNS 缓存
    当在用户客户端查找不到域名对应 IP 地址,则将进入 ISP DNS 缓存中进行查询。比如你用的是电信的网络,则会进入电信的 DNS 缓存服务器中进行查找。

  2. DNS缓存中确实没找到,那就去问找域名服务器要
    2.1 询问根域名服务器
    全球仅有 13 台根域名服务器,1 个主根域名服务器,其余 12 为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com、.cn等)服务器 IP 告诉本地 DNS 服务器
    2.2 询问顶级域名服务器
    顶级域名服务器收到请求后查看区域文件记录,若无记录则将其管辖范围内权威域名服务器的 IP 地址告诉本地 DNS 服务器。
    2.3 询问权威域名(主域名)服务器
    权威域名服务器接收到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确记录。
    2.4 保存结果至缓存
    本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个 IP 地址即可访问目标Web服务器。

面试官可能会打断问到的点:

  1. IPv4 和 IPv6 的区别? 可以参考这个文档

四. 建立TCP连接

在说明怎么建立TCP连接之前,先说明几个前置概念。

TCP是什么?

传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流传输层通信协议,由IETFRFC 793定义。在简化的计算机网络OSI模型中,它完成第四层(传输层)所指定的功能。

为什么要建立TCP连接?

在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换,所以需要建立可靠的TCP连接。

TCP连接如何确保传输的可靠性?

应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来透过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认信息(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失并进行重传。TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和。

TCP数据包结构是什么样子的?

image.png

  • 来源连接端口(16位长)-识别发送连接端口

  • 目的连接端口(16位长)-识别接收连接端口

  • 序列号(seq,32位长)

    • 如果含有同步化旗标(SYN),则此为最初的序列号;第一个资料比特的序列码为本序列号加一
    • 如果没有同步化旗标(SYN),则此为第一个资料比特的序列码。
  • 确认号(ack,32位长)—期望收到的数据的开始序列号。也即已经收到的数据的字节长度加1。

  • 资料偏移(4位长)—以4字节为单位计算出的数据段开始地址的偏移值。

  • 保留(3比特长)—须置0

  • 标志符(9比特长)

    • NS—ECN-nonce。ECN显式拥塞通知(Explicit Congestion Notification)是对TCP的扩展,定义于 RFC 3540 (2003)。ECN允许拥塞控制的端对端通知而避免丢包。ECN为一项可选功能,如果底层网络设施支持,则可能被启用ECN的两个端点使用。在ECN成功协商的情况下,ECN感知路由器可以在IP头中设置一个标记来代替丢弃数据包,以标明阻塞即将发生。数据包的接收端回应发送端的表示,降低其传输速率,就如同在往常中检测到包丢失那样。
    • CWR—Congestion Window Reduced,定义于 RFC 3168(2001)。
    • ECE—ECN-Echo有两种意思,取决于SYN标志的值,定义于 RFC 3168(2001)。
    • URG—为1表示高优先级数据包,紧急指针字段有效。
    • ACK—为1表示确认号字段有效
    • PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
    • RST—为1表示出现严重差错。可能需要重新建立TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
    • SYN—为1表示这是连接请求或是连接接受请求,用于建立连接和使顺序号同步
    • FIN—为1表示发送方没有数据要传输了,要求释放连接。
  • 窗口(WIN,16位长)—表示从确认号开始,本报文的发送方可以接收的字节数,即接收窗口大小。用于流量控制。

  • 校验和(Checksum,16位长)—对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。

  • 紧急指针(16位长)—本报文段中的紧急数据的最后一个字节的序号。

  • 选项字段—最多40字节。每个选项的开始是1字节的kind字段,说明选项的类型。

    • 0:选项表结束(1字节)
    • 1:无操作(1字节)用于选项字段之间的字边界对齐。
    • 2:最大报文段长度(4字节,Maximum Segment Size,MSS)通常在建立连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)字节,携带TCP报文段的IP数据报的长度就不会超过MTU(MTU最大长度为1518字节,最短为64字节),从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
    • 3:窗口扩大因子(3字节,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于65535字节。
    • 4:sackOK—发送端支持并同意使用SACK选项。
    • 5:SACK实际工作的选项。
    • 8:时间戳(10字节,TCP Timestamps Option,TSopt)
      • 发送端的时间戳(Timestamp Value field,TSval,4字节)
      • 时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)
    • 19:MD5摘要,将TCP伪首部、校验和为0的TCP首部、TCP数据段、通信双方约定的密钥(可选)计算出MD5摘要值并附加到该选项中,作为类似对TCP报文的签名。通过 RFC 2385 引入,主要用于增强BGP通信的安全性。
    • 29:安全摘要,通过 RFC 5925 引入,将“MD5摘要”的散列方法更换为SHA散列算法

有了上述知识后,我们可以来表述TCP连接的三次握手建立过程:

TCP建立连接过程

下图是简化版的TCP状态图。更详细的版本见: TCP EFSM 图 (页面存档备份,存于互联网档案馆),包含了ESTABLISHED状态的内部状态。 image.png TCP用三次握手(或称三路握手,three-way handshake)过程建立一个连接。在连接建立过程中,很多参数要被初始化,例如序号被初始化以保证按序传输和连接的强壮性。
一对终端同时初始化一个它们之间的连接是可能的。但通常是由一端(服务器端)打开一个套接字socket)然后监听来自另一方(客户端)的连接,这就是通常所指的被动打开(passive open)。服务器端被被动打开以后,客户端就能开始建立主动打开(active open)。

服务器端执行了listen函数后,就在服务器上建立起两个队列:

  • SYN队列:存放完成了二次握手的结果。 队列长度由listen函数的参数backlog指定。
  • ACCEPT队列:存放完成了三次握手的结果。队列长度由listen函数的参数backlog指定。

image.png 三次握手协议的过程:

  1. 客户端(通过执行connect函数)向服务器端发送一个SYN包,请求一个主动打开。该包携带客户端为这个连接请求而设定的随机数A作为消息序列号。
  2. 服务器端收到一个合法的SYN包后,把该包放入SYN队列中;回送一个SYN/ACK。ACK的确认码应为A+1,SYN/ACK包本身携带一个随机产生的序号B
  3. 客户端收到SYN/ACK包后,发送一个ACK包,该包的序号被设定为A+1,而ACK的确认码则为B+1。然后客户端的connect函数成功返回。当服务器端收到这个ACK包的时候,把请求帧从SYN队列中移出,放至ACCEPT队列中;这时accept函数如果处于阻塞状态,可以被唤醒,从ACCEPT队列中取出ACK包,重新建立一个新的用于双向通信的sockfd,并返回。

如果服务器端接到了客户端发的SYN后回了SYN-ACK后客户端掉线了,服务器端没有收到客户端回来的ACK,那么,这个连接处于一个中间状态,既没成功,也没失败。于是,服务器端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s才知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会断开这个连接。使用三个TCP参数来调整行为:tcp_synack_retries 减少重试次数;tcp_max_syn_backlog,增大SYN连接数;tcp_abort_on_overflow决定超出能力时的行为。

“三次握手”的目的是为了“防止已失效的连接(connect)请求报文段传送到了服务端,因而产生错误”,也即为了解决“网络中存在延迟的重复分组”问题。例如:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。

面试官可能会打断问到的点:

  1. TCP的重传、滑动窗口、流量控制、拥塞控制是是什么?可以参考这个文档
  2. TCP连接释放的四次挥手是什么?可以参考这个文档

五. 为 https 建立SSL/TLS连接

如果请求 url 用的是 https 协议,则需要进行SSL/TLS密钥交换。

为什么需要 https?

http 在传输数据的过程中,所有的数据都是明文传输,安全性难以保障,特别是一些敏感数据,比如用户密码和信用卡信息等,一旦被第三方获取,后果不堪设想。

https 和 http 有什么区别?

HTTPS 相比 HTTP最大的不同就是多了一层 SSL (Secure Sockets Layer 安全套接层)或 TLS (Transport Layer Security 安全传输层协议)。有了这个安全层,就确保了互联网上通信双方的通信安全。

SSL / TLS 以及 SSL / TLS 握手是什么?

SSL 和 TLS 协议可以为通信双方提供识别和认证通道,从而保证通信的机密性和数据完整性。TLS 协议是从Netscape SSL 3.0协议演变而来的,不过这两种协议并不兼容,SSL 已经逐渐被 TLS 取代,所以下文就以 TLS 指代安全层。 TLS 握手是启动 HTTPS 通信的过程,类似于 TCP 建立连接时的三次握手。 在 TLS 握手的过程中,通信双方交换消息以相互验证,相互确认,并确立它们所要使用的加密算法以及会话密钥 (用于对称加密的密钥)。可以说,TLS 握手是 HTTPS 通信的基础部分。

TLS 握手过程

image.png

  1. ClientHello : 客户端会向服务器发送“ClientHello”消息。此消息包含基本信息,包括它支持的 SSL/TLS 版本和可以使用的密码套件,还包括一个客户端产生的随机字符串。
  2. ServerHello:服务器回复“ServerHello”消息,包括双方支持的最高 SSL/TLS 版本和密码套件,还包括一个服务器产生的随机字符串。
  3. 服务器发送数字证书: 服务器将其数字证书提供给客户端以供验证。
  4. 客户端验证和密钥生成:客户端验证服务器的证书。包括验证证书的数字签名、有效期等信息。验证后,它使用服务器的公钥加密“预主密钥”(premaster secret),即唯一的会话密钥,并将其发送回服务器,服务器使用其内部的私钥解密获得预主密钥。
  5. 建立安全连接:服务器和客户端此时都获得了三个字符串(服务端串、客户端串、预主密钥),使用同样的算法计算得到用于加密通信数据的 会话密钥 ,之后该密钥将用于所有通信的对称加密。

面试官可能会打断问到的点:

  1. 对称加密和非对称加密区别是什么?可以参考这个文档
  2. SSL / TLS 使用什么加密算法?
    密钥交换过程中使用非对称加密,比如RSA、PSK算法; 交换得到会话密钥后使用该密钥对称加密数据,比如DES、AES、RC2、RC4算法。 这种既使用对称加密,也使用非对称加密算法的方法叫做 混合加密。具体使用的对称及非对称加密算法在不同 SSL/TLS 协议版本有所不同,详情可以参照 传输层安全性协议
  3. 相对于http,https 有什么缺点?
    3.1 慢,要加密解密;
    3.2 贵,证书使用要钱;

六. 发起请求

TCP连接建立之后,浏览器向服务器发起http请求(后续https的加密特性不再是我们关心的重点,二者并列场景直接写作 http)。

这里有一个TCP连接和http结合的问题。
http1.0 时代,默认使用的是 短连接,也就是说,浏览器和服务器每进行一次http操作,就建立一次TCP连接,任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个http会话。

http1.1 起,默认使用 长连接,即建立一个TCP连接可以传输多个http请求。使用长连接的http协议,会在响应头加入这个配置:Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。

然后 http1.1 版本有一些问题依然没有解决。比如 队头阻塞 问题,意思是一个TCP长连接允许多条http请求通过管道化的方式同时发送,但是这种数量是有上限的,如果占满的话,之后的http请求必须等待前面请求响应结束,释放占用连接资源后才可以发送。那么对于某些耗时长的请求,比如没有拆分chunk的大块js,或者大图片,或者其他一些出现异常丢包的情况,其相关http请求会一直占据TCP连接得不到释放,而其他小得多的资源请求则被阻塞在外边,长期得不到及时支持。而对于页面来说, 资源的优先级、重要性跟其体积、请求难度并没有直接关系。

http2 使用 多路复用 的方式解决了队头阻塞问题,具体来讲,采用 二进制分帧层,将请求拆解为一帧一帧的请求,每一帧请求都带上独特的编号,服务端根据此编号区分拼接完整的请求体。这样,耗时长的大块http请求被打散成了大小上限可控的一系列帧,不再能长期阻塞后续请求。

http3 使用了 QUIC协议,大致来讲,就是既有TCP的可靠性,又有UDP的速度优势。

七. 服务端处理请求

服务端收到请求后开始处理。
首先判断资源是否可以缓存,主要依据就是请求头的 if-none-matchif-modified-since 字段,这两个字段数值的来源是服务端上次响应时响应头的 etaglast-modified 字段。如果可以缓存的话,赋304状态码响应客户端,让客户端继续使用本地缓存。有必要的话,通过响应头的 etaglast-modified 字段更新客户端的相应字段,以便于下次判断。

HTTP 响应状态码用来对表明特定 HTTP 请求的处理情况。 响应被归为以下五大类,具体:

  1. 信息响应 (100199)
  2. 成功响应 (200299)
  3. 重定向消息 (300399)
  4. 客户端错误响应 (400499)
  5. 服务端错误响应 (500599)

以上状态码由 section 10 of RFC 2616定义。

八、浏览器渲染页面

浏览器的渲染进程负责选项卡内页面的渲染。按照渲染的时间顺序,渲染过程可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。

构建DOM树

浏览器无法直接理解和使用HTML,需要将HTML转化为浏览器能理解的结构-DOM。
DOM 是浏览器的页面内部表示,也是Web开发人员你可以通过JavaScript进行交互的数据结构和API。
当渲染进程收到导航的提交消息并开始接收HTML数据时,主线程开始解析HTML文本字符串,并将其转换为DOM。

样式计算

拥有DOM不足以了解页面的外观,因为可以在CSS中设置页面元素的样式。主线程解析CSS并确定每个DOM节点的计算样式。
即使不提供任何CSS,每个DOM节点也有一个计算样式。比如 h1 标签显示地比 h2 标签大;p 标签有默认边距等等。这是因为浏览器有一个默认的样式表(user agent stylesheet)

布局

现在渲染进程知道文档的结构和每个节点的样式,但还不足以渲染页面,因为二者还需要结合起来,知道实际页面的效果。
布局是寻找页面元素几何特征的过程。主线程遍历DOM和计算样式并创建布局树(LayoutTree),包括坐标和边界框大小等信息。布局树与DOM树的结构类似,但它只包含与页面上可见内容相关的信息,比如某元素设置了 display: none 属性,则其不存在于布局树中;而如果某元素拥有伪元素,则该伪元素虽然不在DOM树中,但是会存在于布局树中。

分层

现在我们有了布局树,而且每个元素的具体位置信息都计算出来了,那么接下来是不是就要开始着手绘制页面了?
答案依然是否定的。因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)
具体的分层过程是:

  1. 遍历布局树,判断其每个节点是否可以分层,分层的条件是:
    1.1 节点拥有层叠上下文属性
    1.2 节点需要剪裁(clip)。比如某div固定宽高像素值,而内部内容超过其固定大小,则div与其内容会进行分层。
  2. 如果某个节点不会分成,则进入其父节点的层。

绘制

在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制。 渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。
可以打开“开发者工具”的“Layers”标签,选择“document”层,查看具体分层和绘制命令。

栅格化

绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。
当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程,合成线程会将图层划分为图块(tile),这些图块的大小通常是 256x256 或者 512x512,然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。
所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。
通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。

合成和显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。 浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

浏览器绘制总结

到这里,经过这一系列的阶段,编写好的 HTML、CSS、JavaScript 等文件,经过浏览器就会显示出漂亮的页面了。
一个完整的渲染流程大致可总结为如下:

  1. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
  2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
  3. 创建布局树,并计算元素的布局信息。
  4. 对布局树进行分层,并生成分层树。
  5. 为每个图层生成绘制列表,并将其提交到合成线程。
  6. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
  7. 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
  8. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。

参考文档:

  1. 深入了解现代网络浏览器
  2. 多张图带你彻底搞懂DNS域名解析过程
  3. 干货分享 | 一文读懂DNS原理及解析过程
  4. 一文彻底搞懂 TCP三次握手、四次挥手过程及原理
  5. 35 张图解:被问千百遍的 TCP 三次握手和四次挥手面试题
  6. 维基百科:传输控制协议
  7. HTTPS详解二:SSL / TLS 工作原理和详细握手过程
  8. SSL官网握手解释
  9. HTTPS详解二:SSL / TLS 工作原理和详细握手过程
  10. HTTP长连接和短连接
  11. 极客时间:浏览器工作原理(李兵)