当我们在浏览器地址栏中输入一个网址会发生什么

原文见 what happens when

这篇文章旨在尽可能详细的解释一个经典的面试问题“当你在浏览器的地址栏键入’google.com’并按下enter键,会发生什么”

当你在键盘上按下‘g’

接下来的几节会解释所有有关键盘输入和操作系统中断的东西。但是之后发生的一大堆的事情是没有解释的。当你只是按下了’g’这个键,浏览器就会接收到这个事件,接下来浏览器的自动完成机制就会运行。根据你浏览器的算法以及你是否开启的隐私\无痕模式,网址栏的下拉框中会向你显示各种各样的建议。大多数算法会将历史搜索记录以及书签优先排在前面。反正你都要输入’google.com’,所以这些建议都不影响,但是在你最终输入完整的网址之前一大堆代码都在运行,并且每一次按下一个键这些建议都会改进。甚至在你输入网址之前就向你建议’google.com’。

按下enter键

让我们选择按下enter键,击中底部为起点。在这个时刻,被按下的键专用的电路被闭合(直接或电容式)。这使得少量电流流入键盘的逻辑电路,该逻辑电路会扫描每一个键开关的状态,消除开关快速断续闭合的电气噪声,并且将其转换为一个按键编码,(译者:每一个键对应一个编码,参考http://blog.csdn.net/zhaozhbcn/article/details/38852583),在这里Enter键对应的是13。然后主机键盘控制器负责将按键编码再编码成计算机能理解的码字并传输给计算机。现在一般通过通用串行总线(USB)或者蓝牙连接,以前通过PS/2 或者 ADB连接。

如果使用的是USB键盘

  • 键盘的USB电路由计算机的USB主控制器上的引脚1提供的5V电源供电。
  • 产生的按键编码由内部键盘电路存储器存储在一个叫“终端”的寄存器中。
  • 主机键盘控制器每10ms(由键盘声明的最小时间)获取“终端”中的值,所以它能够得到存放在寄存器中的按键编码。
  • 这个编码由SIE(串行接口引擎)根据低级USB协议转化为USB数据包。
  • 这些数据包以不同的电子信号以最高速率1.5M/s从(中间的两个)D+和D-引脚发送,因为HID(人机接口设备)总是被声明为“低速度设备”(usb2.0规格)
  • 这个串行信号被计算机的主机控制器编码,由计算机的HID通用键盘设备驱动产生中断。这个键盘的编码便传入操作系统的硬件抽象层。

如果使用的是虚拟(触屏设备)键盘

  • 当用户将手指放在现代的电容式触摸屏上时,会有少量的电流转移到手指上。这形成了一个通过导电层的静电场的电路,并在触屏的位置产生一个电位差。屏幕控制器产生一个中断来报告按键的坐标。
  • 然后移动操作系统在其GUI元素之一(现在是虚拟键盘应用程序按钮)中通知当前关注的应用程序的按键事件。
  • 虚拟键盘产生软中断,发送一个按下键盘的消息给操作系统。
  • 操作系统通知当前关注的这个应发生的这个按键事件。

中断の焰(非USB键盘)

(译者注:实在不知道怎么翻译这个小标题:interrupt fires)
键盘发送信号到其中断请求队列,一类中断请求由中断控制器映射到一个中断向量。CPU使用IDT(Interrupt Descripter Table,中断描述符表)将一个中断向量映射到由内核提供的处理该中断的程序(interrupt handlers)。当一个中断到达,CPU检索中断描述符表,找到对应的中断向量,运行其处理程序。此时,内核登场了。

(Windows上)WM_KEYDOWN信息被发送给应用程序

HID(人机交互设备)传输系统将按下键盘这个事件传给KBDHID.sys驱动,这个驱动会将HID用法转化成扫描码。在这里这个扫描码是VK_RETURN(0x0D)。KBDHID.sys驱动和KBDCLASS.sys(keyboard class driver)进行接合。这个驱动文件负责以一种安全的方式处理所有的键盘和键区输入。然后它调用Win32K.sys(在通过可能安装的第三方键盘过滤器传递消息之后)。这些都发生在内核态。

Win32K.sys 通过 GetForegroundWindow() API明确那个窗口处于活跃(active)状态。这个API提供了浏览器地址栏的窗口句柄。Windows消息泵调用SendMessage(hWnd, WM_KEYDOWN, VK_RETURN, lParam)lParam是位掩码用于指示按键更多的信息:重复次数(这里是0),真正的扫描码(可依赖于原始设备制造商,但通常在VK_RETURN情况下不是),是否是扩展的键(如alt, shift, ctrl)被按下(在这里不是),以及其他一些状态。

Windows的SendMessage API是一个简单的函数,它将消息添加到特定的窗口句柄(hWnd)的消息队列中去。然后,调用分配给hWnd的主要的消息处理函数(叫做WindowProc)来处理这个消息队列中的每一条消息。

活动的窗口(hWnd)实际上是一个编辑控件,在这种情况下WindowProc具有WM_KEYDOWN消息的消息处理程序。 此代码在传递给SendMessage(wParam)的第三个参数中查找,因为它是VK_RETURN,所以知道用户已经按下了ENTER键。

(MAC OS上)NSEvent会发送给应用程序

中断信号触发在I/O Kit kext 键盘驱动程序中的中断事件。驱动程序将信号转化为按键编码传送给OS X 的WindowServer进程。WindowServer通过其Mach端口将事件分派到任何适当的(例如活跃的或监听中的)应用程序中,并将其放置到事件队列中。事件可以被有着足够权限的线程通过调用mach_ipc_dispatch函数从事件队列中读出。这通常通过NSEventType KeyDownNSEvent发生,并由NSApplication主事件循环处理。

(在GNU/Linux上)Xorg服务程序监听键盘编码

当使用图形化界面X server时,X会使用通用事件驱动程序evdev来获取按键事件。然后使用X server特定的键盘映射和规则将键码重新映射到扫描码。扫描码的映射完成之后X server将字符发送给window manager(比如,DWM, metacity, i3, etc),window manager再把字符发送给指定的窗口。这个窗口的图形化API接收到这个字符在正确的获得焦点的地方以合适的字体符号显示出来。

解析URL

现在浏览器有了包含在url中的如下信息:

  • 协议 ‘http’
    使用的是超文本传输协议
  • 资源 ‘/’
    检索根目录

判断内容是URL还是搜索条目

当并非协议或者有效域名的内容提供给浏览器进行处理的时候,地址栏中的内容就传送给浏览器默认的搜索引擎。很多情况下URL有特殊的文本块连接在其后面告诉搜索引擎它来自哪一个浏览器地址栏。

在主机名中转换非ASCII的Unicode字符

  • 浏览器检查主机名中的字符是否在a-z,A-Z, 0-9, -, or .
  • 因为这次输的是 google.com所以没什么,但是如果有的话,浏览器会将Punycode编码应用到URL的主机部分。

(译者注:早期的DNS(Domain Name System)是只支持英文域名解析。在IDNs(国际化域名Internationalized Domain Names)推出以后,为了保证兼容以前的DNS,所以,对IDNs进行punycode转码,转码后的punycode就由26个字母+10个数字,还有“-”组成。)

检查HSTS列表

  • 浏览器检查其“预加载的HSTS(HTTP Strict Transport Security,HTTP严格传输安全)”列表。这是一个要求只能通过HTTPS连接的网址的列表。
  • 如果这个网址在这个列表上,那么浏览器就会使用HTTPS而不是HTTP发送它的请求。否则,初始化连接请求就是使用HTTP发送。(注意,网站仍然可以使用HSTS策略,而不需要在HSTS列表中。 用户向网站发送的第一个HTTP请求将会收到一个响应,请求用户只发送HTTPS请求。 但是,这个单一的HTTP请求可能会使用户容易遭受“降级攻击”,这就是为什么HSTS列表被包含在现代Web浏览器中的原因。)

DNS查询

  • 浏览器先检查该域名是否在其缓存中。(Chrome浏览器的DNS缓存可以在chrome://net-internals/#dns 看到)。
  • 如果缓存中没有,它就调用gethostbyname库函数(根据具体的操作系统有所差别)进行查询。
  • gethostbyname在使用DNS解析主机名之前会检查本地host文件(位置根据具体的操作系统有差别)看是否能够解析主机名。
  • 如果gethostbyname既没有缓存改主机名,在host文件中也没有找到,则发送请求到网络堆栈中配置的DNS服务器,通常来说是本地服务器或者ISP(因特网服务提供商)的缓存DNS服务器。
  • 如果DNS服务器在同一个子网上,那么网络库将为DNS服务器执行ARP 过程
  • 如果DNS服务器位于不同的子网上,则网络库将为使用默认网关IP执行ARP 过程

APR过程

要发送一个ARP(Address Resolution Protocol,地址解析协议)广播,网络堆栈库需要一个IP地址用于查询。它也需要知道用来发送这个ARP广播的接口的MAC地址。

首先检查APR缓存是否包含目标IP地址,如果是,则返回结果:目标 IP 地址= 对应的MAC。

如果这个条目不在缓存中:

  • 查询路由表看目标PI地址是否在路由器表的某个子网内,如果是,这个库函数就会使用和那个子网相关联的接口,如果不是,则使用和默认网关相关联的接口。
  • 所选择的网络接口的MAC地址呗查询到。
  • 网络库发送一个第二层的请求(数据链路层,根据OSI七层模型)的ARP请求。

ARP Request:

Sender MAC: interface:mac:address:here
Sender IP: interface.ip.goes.here
Target MAC: FF:FF:FF:FF:FF:FF (Broadcast)
Target IP: target.ip.goes.here

根据计算机和路由器之间的硬件类型:

直接相连:

  • 如果计算机和路由器直接相连,路由器返回一个ARP Reply的响应(见下面)。

集线器:

  • 如果计算机和一个集线器相连,这个集线器会广播这个ARP请求给其他的端口。如果集线器和某个路由器相连,则路由器返回一个ARP Reply的响应(见下面)。

交换机:

  • 如果计算机是和一个交换机相连,交换机检查它本地CAM/MAC表来看哪一个端口有正在查询的MAC地址。如果交换机没有这个MAC地址的条目,它将广播给其它端口。
  • 如果交换机本地CAM/MAC表有这个条目,它会发送ARP请求到有这个MAC地址的端口。
  • 如果路由器正好连接在了这个端口,则路由器返回一个ARP Reply的响应(见下面)。

ARP Reply:

Sender MAC: target:mac:address:here
Sender IP: target.ip.goes.here
Target MAC: interface:mac:address:here
Target IP: interface.ip.goes.here

现在网络库函数有了不管是DNS服务器或者可以进行DNS解析进行的默认网关的IP地址了。

  • 53号端口用于发送一个UDP请求到DNS服务器。(如果响应的数据包很大,则会使用tcp协议代替)。
  • 如果本地/ISP 的DNS服务器无法查询到该域名,则会根据DNS服务器列表递归查询,直到查找到起始授权机构。如果查询到了,则返回该结果。

打开一个套接字

一旦浏览器得到了目标服务器的IP地址,它会使用它并且加上一个端口号,端口号根据url中使用的协议有所不同,(http是80端口,而https是443端口),然后调用一个系统库函数socket,请求一个TCP套接字,AF_INET/AF_INET6SOCK_STREAM

  • 这个请求首先发送给传输层,TCP数据包分段在这个层生成,目的端口被加在tcp协议头部,从内核的动态端口范围中选择一个源端口号(Linux中叫做ip_local_port_range )
  • tcp分段被发送往网络层,在这一层加上IP头部。再给每一帧加上机器网卡的MAC地址以及网关的MAC地址,就像前面一样,如果内核不知道网关的MAC地址,就需要广播ARP请求得到MAC地址。

在这个时刻数据包就准备好通过一下几种网络进行传输了:

  • 以太网
  • WIFI
  • 蜂窝数据通信网络

对大多数家庭或者小型公司互联网连接来说,这个数据包会通过你的电脑,可能通过一个本地网络,然后通过一个调制解调器(俗称的‘猫’),将数字信号0和1转换成模拟信号以便在电话、电缆或者无线电话连接中传输。在这个连接的另一端,有另一台调制解调器将模拟信号转化为数字信号可以在下一个网络节点中进行处理,在这些节点,这个数据包的源主机和目的主机的地址可以得到进一步的分析。

大多数大型企业和一些较新的住宅连接将具有光纤或直接以太网连接,在这种情况下数据保持数字化并直接传递到下一个网络节点进行处理。

最终,数据包将到达管理本地子网的路由器。从这里,它会继续跨越自制系统的边界路由器以及其他自治系统,最终到达目的服务器。在这条路上的每一个路由器都会提取IP头部中的目的地址将其送到合适的下一跳,这个包的生存时间每经过一跳便会减少1,如果TTL字段达到零,或者当前路由器的队列中没有空间(可能由于网络拥塞),数据包将被丢弃。

这样的发送以及接受过程会在以下的TCP连接中发生很多次:
(译者注:TCP三次握手过程,TCP头部见下图)
TCP头部格式

  • 客户端选择一个初始化序列号(ISN)填入序列号字段并且发送一个SYN标志位置为1的TCP数据包指明他设置了初始化序列号。
  • 服务器收到SYN包并且服务器也处在一个合适的状态(译者:大概就是服务器有资源可以提供吧)
    • 服务器选择它的初始序列号
    • 置SYN标志位置为1
    • 复制客户端的序列号并加1到ACK字段,将ACK标志位置1表明它确认收到第一个数据包
  • 客户端发送一个数据包确认连接
    • 将之前发送的那个序列号加1
    • 将收到的ACK号加1(译者:存疑)
    • 将ACK标志位置1

(根据译者所知这个步骤应该是,客户端接受到服务器的ACK包,要进行确认则将服务器的序列号加1填入ACK字段,将ACK标志位置1,序列号是之前发送的那个SYN包的序列号加1,将数据包发送给服务器端)

这个时候连接建立完成。

  • 数据按以下方式传输
    • 如果哪一方传输了N字节的数据,将序列号加上N
    • 如果另一方要确认收到了一个数据包或者若干个数据包,他发送的ACK包中的ACK号需要等于最后收到那个数据包的序列号。
  • 关闭连接
    • 关闭者发送一个FIN包
    • 另一发送ACK包响应这个FIN包,并发送自己的FIN包
    • 关闭者发送ACK包确认上一个FIN包

TLS握手

  • 客户端向服务器发送ClientHello消息,该消息包括TLS版本号,加密算法套件,以及可用的压缩方法。
  • 服务器返回一个ServerHello消息,内容包括TLS版本号,选择的加密方法和压缩方法,以及服务器的由CA(认证中心)认证的公钥证书。证书包含一个公钥,客户端将使用该公钥来加密握手的其余部分,直到协商好对称密钥为止。
  • 客户端对比它所信任的CA的列表来验证服务器的数字证书。如果可以建立起基于这个CA的信任,客户端产生一串伪随机字节,并用服务器的公钥进行加密。这些随机字节将用于决定最后的对称密钥。
  • 服务器端使用自己的私钥解密消息得到伪随机字节,并使用它们生成对称主密钥。
  • 客户端发送Finished消息给服务器,使用对称密码加密了这一次的传输的哈希值。
  • 服务器根据消息生成了自己的hash值,并对比客户端发送的hash值看是否相等。如果相等,它将用对称密钥加密自己的Finished消息发送给客户端。
  • 从现在开始TLS回话将使用两者协商好的对称密钥进行加密HTTP数据。

HTTP 协议

如果所使用的Web浏览器是由Google编写的,则不会发送HTTP请求来检索这个页面,而是会发送一个请求,尝试与服务器协商从HTTP到SPDY协议的“升级”。

(译者注:SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%。)

如果客户端使用HTTP协议,并不支持SPDY协议,它会发送一个如下形式的请求给服务器:

GET / HTTP/1.1
Host: google.com
Connection: close
[other headers]

其中[other headers]指的是按照HTTP规范格式化的一系列以冒号分隔的键值对,并由单个新行分隔。(这假定正在使用的Web浏览器没有任何违反HTTP规范的错误。 这还假定Web浏览器使用HTTP / 1.1,否则它可能不包含请求中的Host头部,GET请求中指定的版本将为HTTP / 1.0HTTP / 0.9。)

HTTP/1.1为发送者定义了“关闭”连接选项,发出信号表明在完成这个响应之后连接将关闭。例如:

Connection: close

不支持持久连接的HTTP/1.1 应用程序必须在每条消息后面包含关闭连接选项。

在发送了请求和头部之后,浏览器发送一行新的空行给服务器表示自己的请求内容发送完成。

服务器返回一个表示请求状态的响应码,并用以下格式的响应进行响应:

200 OK
[response headers]

接着发送一个新的空行。在发送装有www.google.com的HTML内容。这时服务器或者关闭连接,或者按照客户端发送的请求头部中要求的那样,保持连接以便利用这次连接进行更多的请求。

如果由浏览器发送的头部中包含足够的信息可以让web服务器判断自从上次检索(即,如果网页浏览器包括ETag头部)以来web浏览器缓存的文件的版本是否未被修改, 可以改为以表格的请求回应:

304 Not Modified
[response headers]

然后服务器就不发送网页内容了,web浏览器会自己就会从自己的缓存中检索HTML内容。

在解析HTML之后,网页浏览器(和服务器)为HTML页面引用的每个资源(图像,CSS,favicon.ico等)重复这个过程,除了GET / HTTP / 1.1之外,请求将是GET/$(相对于www.google.com的网址)HTTP / 1.1

如果HTML引用的是别的域名的资源而不是www.google.com,浏览器回到解析域名,重复所有步骤。请求中的Host头部也会被设置为其他合适的服务器名而不是goole.com

HTTP 服务器请求处理

HTTPD(HTTP 守护进程)服务器在服务器端专门处理请求/响应。最常见的HTTPD服务器是用于Linux操作系统的Apache 或者 nginx ,以及用于Windows系统的IIS。

  • HTTPD 接受请求。
  • 服务器将请求分解为一下参数:
    • HTTP请求方法:GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, 或者 TRACE其中的一种。在url直接输入地址栏的情况下,方法是GET
    • 域名,在这里是goole.com。
    • 请求路径或者页面,在这里是 / (在没有指明路径或者页面的情况下,/是默认路径)
  • 服务器验证是否配置了google.com 对应的虚拟主机。
  • 服务器验证google.com是否接受GET请求。
  • 服务器验证客户端是否可以使用该请求方法(通过IP地址,认证等)
  • 如果服务器安装了重写模块,(比如Apache的mod_rewrite 或者 IIS的 URL Rewrite),服务器会先将请求和其中的配置规则进行匹配,如果匹配规则找到了,服务器使用这个规则重写这条请求。
  • 服务器获取与请求对应的内容,在这里它会回到到索引文件,因为/是根目录,(有的情况会重写,但这是最普遍的方法)。
  • 服务器根据处理程序解析文件。如果Google运行在PHP上,服务器根据PHP解释这个索引文件,发送结果给客户端。

浏览器背后

一旦服务器向浏览器提供了这些资源(HTML, CSS, JS, images, 等),浏览器经历如下几步:

  • 解析 - HTML,CSS,JS
  • 渲染 - 构建DOM树→渲染树→渲染树的布局→绘制渲染树

浏览器

浏览器的功能是通过从服务器那请求资源以及展示在浏览器窗口中来展现你所选择的资源。资源通常是HTML文件,也有可能是PDF文件,图片或者其他类型的内容。这些资源的位置通过用户使用URI(Uniform Resource Identifier,统一资源标识符)指明。

浏览器解释和显示HTML文件的方式由HTML和CSS规范中指定。这些规范由为W3C组织(World Wide Web 联盟)维护,W3C是web的标准组织。

浏览器用户界面有很多共同之处。 常见的用户界面元素包括:

  • 插入URI的地址栏
  • 回退和前进的按钮
  • 书签选项
  • 刷新和停止按钮用于刷新和停止对当前文档的加载
  • Home按钮,可以返回Home页面

浏览器高级结构

浏览器的组件有:

  • 用户界面:用户界面包括地址栏,后退/前进按钮,书签菜单等。除了可以看到你请求的那个页面的窗口,浏览器的每个部分都有所显示。
  • 浏览器引擎:浏览器引擎编排用户界面和渲染引擎之间的行为。
  • 渲染引擎:渲染引擎负责展示请求的页面内容。比如如果请求的内容是HTML,渲染引擎解析HTML和CSS,将解析的内容展现在屏幕上。
  • 网络:网络组件处理诸如HTTP请求之类的网络调用,在独立于平台的接口后面,根据不同平台,有着不同的实现。
  • UI后端:UI后端用于绘制组合框和窗口等基本小部件。 这个后端公开了一个不是特定于平台的通用接口。
  • JavaScript引擎:用于解析并执行JS脚本。
  • 数据存储:数据存储是一个持久层。浏览器需要在本地保存所有类型的数据,比如cookies。浏览器也支持各种存储机制如:localStorage, IndexedDB, WebSQL 以及 FileSystem。

HTML解析

渲染引擎从网络层得到请求文档的内容开始。这通常在8kB大小的chunk中完成。

HTML解析器的主要工作是将HTML标记解析为解析树。

这个输出的树(解析树)是一棵DOM元素以及属性节点的树。DOM是Document Object Model(文档对象模型)的简写。它是HTML文档的对象表示,以及HTML元素对外面的世界如JS的接口。这棵树的跟是“Document”对象。在通过脚本进行任何操作之前,DOM与标记之间几乎有一对一的关系。

解析算法

HTML不可以用常规的自顶向下或者字底向上的解析器解析。

原因如下:

  • 语言的宽容性。
  • 浏览器具有传统的容错能力来支持众所周知的无效HTML案例。
  • 解析过程是可重入的。对于其他语言,在解析过程中源代码不会改变,但在HTML中,动态代码(如包含document.write()调用的脚本元素)可以添加额外的标记,因此解析过程实际上会修改输入。

因为无法使用常规的解析技术,浏览器使用自定义的解析器来解析HTML代码。解析算法在HTML5规范中有详细描述。

算法包含两个阶段:标记化和构建树

当解析完成之后的行为

浏览器获取这个页面引用的额外的资源((CSS, images, JavaScript files, 等)。

在这一阶段,浏览器将文档标记为交互式,并开始解析处于“延迟”模式的脚本:在解析文档之后应执行的脚本。 文档状态设置为“完成”,并触发“加载”事件。

注意:在HTML页面中不存在无效的语法。浏览器会修复无效的内容并继续。

CSS解释

  • 使用‘CSS词法和语法’解析CSS文件,<style>标签内容,style属性值。
  • 每一个CSS文件被解析成StyleSheet对象,每个对象都包含具有选择器和对象的CSS语法的CSS规则。
  • 当使用特定的解析器生成器时,CSS解析器可以是自顶向下或者自下而上的。

页面渲染

  • 遍历DOM节点生成帧树或者渲染树,并为每一个节点计算CSS样式的值。
  • 通过将子节点的首选宽度和节点的水平边界,边界和填充值相加,计算“框架树”中每个节点的首选宽度。
  • 通过将每个节点的可用宽度分配给子节点,从上到下计算每个节点的实际宽度。
  • 通过应用文本换行和总计子节点高度和节点的边界,边界和填充来计算每个节点的高度。
  • 使用上面的计算结果计算每个节点的坐标。
  • 如果元素是floated,位置是absolutely或者relatively,更或者使用了其他更复杂的特性,那么渲染阶段会有更复杂的步骤。详情参见 http://dev.w3.org/csswg/css2/ http://www.w3.org/Style/CSS/current-work
  • 创建图层来描述页面的哪些部分可以作为一组进行动画,而不用重新栅格化。 每个帧/渲染对象被分配给一个图层。
  • 给页面的每一层分配纹理。
  • 遍历每个图层的帧/渲染对象,并为其各自的图层执行绘图命令。 这可能会被CPU光栅化,或者使用D2D / SkiaGL直接在GPU上绘制。
  • 上述所有步骤可能会重利用上一次页面被渲染时计算的结果,这样的话额外的改变会要求做少量的工作。
  • 页面图层被发送到合成过程,在那里它们与其他可见内容(如浏览器镶边,iframe和附加面板)的图层相结合。
  • 计算最终图层位置,并通过Direct3D / OpenGL发布复合命令。 GPU命令缓冲区被刷新到GPU进行异步渲染,帧被发送到窗口服务器。

GPU渲染

  • 在渲染过程中,图形计算层也可以使用通用CPU或图形处理器GPU。
  • 在使用GPU进行图形渲染计算时,图形软件层会将任务切割成多个部分,因此它可以利用GPU强大的并行处理能力来进行渲染过程所需的浮点计算。

Windows 服务器

后期渲染和用户引发的执行

渲染完成之后,浏览器将执行JS代码可能是因为一些定时机制(比如一个Google涂鸦动画),或者是用户的交互(在搜索框中输入请求并受到建议)。插件或者Flash也有可能执行,尽管不是在这次的Google主页上。脚本也会造成额外的网络请求,也会修改这个页面或者它的页面布局,也会引发其他的页面渲染和绘图过程。

猜你喜欢

转载自blog.csdn.net/banzhihuanyu/article/details/79052652