就像咱们以前文章中提到的渲染引擎同样,咱们认为好的和优秀的JavaScript开发人员之间的区别在于,后者不只了解语言的基本要素,还要了解其内部原理和周围环境。chrome
四十九年前,建立了一个名为ARPAnet的东西。这是一个早期的分组交换网络,也是实现TCP / IP套件的第一个网络。该网络在加州大学和斯坦福研究院之间创建了联系。 20年后,Tim Berners-Lee发布了一个名为“Mesh”的提案,该提案后来更为人称为万维网。在那49年里,互联网已经走过了漫长的道路,从两台计算机交换数据包开始,到达超过7500万台服务器,38亿人使用互联网和1.3B网站。浏览器
在这篇文章中,咱们将尝试分析现代浏览器采用哪些技术来自动提高性能,而且咱们将特别放大浏览器网络层。最后,咱们将提供一些关于如何帮助浏览器提高Web应用性能的想法。缓存
现代网络浏览器专为快速,高效和安全地交付网络应用/网站而设计。数百个组件运行在不一样的层上,从流程管理和安全沙箱到GPU流水线,音频和视频等等,Web浏览器看起来更像是一个操做系统,而不只仅是一个软件应用程序。安全
浏览器的总体性能取决于许多大型组件:解析,布局,样式计算,JavaScript和WebAssembly执行,渲染,固然还有网络堆栈。性能优化
工程师常常认为网络堆栈是一个瓶颈。这一般是这种状况,由于在解除其余步骤以前,须要从互联网获取全部资源。为了提升网络层的效率,它不只须要扮演简单的套接字管理员的角色。它做为一种很是简单的资源获取机制呈现给咱们,但它其实是一个拥有本身的优化标准,API和服务的整个平台。服务器
做为Web开发人员,咱们没必要担忧单个TCP或UDP数据包,请求格式化,缓存和其余全部事情。整个复杂性由浏览器处理,所以咱们能够专一于咱们正在开发的应用程序。可是,了解发生了什么,能够帮助咱们建立更快,更安全的应用程序。cookie
实质上,用户开始与浏览器交互时发生了如下状况:网络
W3C Navigation Timing规范提供浏览器API以及浏览器中每一个请求的生命周期背后的时间和性能数据。让咱们来看看这些组件,由于它们在提供最佳用户体验方面起着相当重要的做用:架构
整个联网过程很是复杂,有许多不一样的层次可能会成为瓶颈。这就是为何浏览器努力经过使用各类技术来提升性能的缘由,以便整个网络通讯的影响最小。app
让咱们从一些术语开始:
JavaScript和WebAssembly不容许咱们管理单个网络套接字的生命周期,这是一件好事!这不只可让咱们的手保持清洁,并且还可让浏览器自动进行大量的性能优化,其中一些包括套接字重用,请求优先级和后期绑定,协议协商,强制链接限制等等。
实际上,现代浏览器会花费更多的时间来将请求管理周期与套接字管理分开。套接字按池组织,按原点分组,每一个池强制实施本身的链接限制和安全约束。待处理的请求排队,优先,而后绑定到池中的单个套接字。除非服务器有意关闭链接,不然能够在多个请求中自动重用相同的套接字!
因为新的TCP链接的开通须要额外的成本,所以链接的重复使用对其自己具备很大的性能优点。默认状况下,浏览器使用所谓的“keepalive”机制,这能够节省在发出请求时打开新链接到服务器的时间。打开一个新的TCP链接的平均时间是:
这种架构打开了其余一些优化机会的大门。这些请求能够根据其优先级以不一样的顺序执行。浏览器能够优化全部套接字上的带宽分配,或者能够在预期请求时打开套接字。
正如我以前提到的,这一切都是由浏览器管理的,并不须要咱们的任何工做。但这并不必定意味着咱们无能为力。选择正确的网络通讯模式,传输类型和频率,选择协议以及调整/优化服务器堆栈能够在提升应用程序的总体性能方面发挥重要做用。
有些浏览器甚至更进一步。例如,Chrome能够自我教导本身在使用它时变得更快。它根据访问的网站和典型的浏览模式进行学习,以便在用户作任何事情以前预测可能的用户行为并采起行动。最简单的例子是当用户在连接上悬停时预先呈现页面。若是您有兴趣了解更多关于Chrome优化的信息,请参阅本章的https://www.igvita.com/posa/h...。
容许浏览器管理单个套接字具备另外一个很是重要的目的:经过这种方式,浏览器能够对不可信的应用程序资源执行一致的安全和策略约束。例如,浏览器不容许直接API访问原始网络套接字,由于这可使任何恶意应用程序与任何主机进行任意链接。浏览器还强制执行链接限制,以保护服务器以及客户端免受资源耗尽。
浏览器格式化全部传出请求,以强化一致且格式良好的协议语义来保护服务器。一样,响应解码自动完成,以保护用户免受恶意服务器的侵害。
传输层安全性(TLS)是一种经过计算机网络提供通讯安全性的加密协议。它在许多应用程序中普遍使用,其中之一是网页浏览。网站可使用TLS来保护其服务器和Web浏览器之间的全部通讯。
整个TLS握手由如下步骤组成:
客户端向客户端发送“Client hello”消息,以及客户端的随机值和支持的密码套件。
服务器经过向客户端发送“服务器问候”消息以及服务器的随机值进行响应。
服务器将其证书发送给客户端,并能够向客户端请求相似的证书。服务器发送“服务器已完成”消息。
若是服务器已经从客户端请求证书,则客户端发送它。
客户端建立一个随机的预主密钥,并使用服务器证书中的公钥对其进行加密,并将加密的预主密钥发送给服务器。
服务器收到预主密钥。服务器和客户端根据预主密钥生成主密钥和会话密钥。
客户端向服务器发送“更改密码规格”通知,指示客户端将开始使用新的会话密钥进行散列和加密消息。客户端还发送“客户端已完成”消息。
服务器收到“更改密码规范”并使用会话密钥将其记录层安全状态切换为对称加密。服务器向客户端发送“服务器已完成”消息。
客户端和服务器如今能够经过他们创建的安全通道交换应用程序数据。全部从客户端发送到服务器并返回的消息均使用会话密钥加密。
若是任何验证失败 - 例如服务器正在使用自签名证书,则警告用户。
若是两个页面的协议,端口(若是指定了一个)和主机相同,则两个页面具备相同的来源。
如下是可能嵌入跨源的资源的一些示例:
带有<script src =“...”> </ script>的JavaScript。语法错误的错误消息仅适用于同源脚本
CSS <link rel =“stylesheet”href =“...”>。因为CSS的宽松语法规则,跨源CSS须要正确的Content-Type标头。浏览器的限制因人而异
带有<img>的图像
带有<video>和<audio>的媒体文件
带有<object>,<embed>和<applet>的插件
带有@ font-face的字体。有些浏览器容许使用交叉来源的字体,其余浏览器则须要相同来源的字体。
任何与<frame>和<iframe>的东西。网站可使用X-Frame-Options标题来阻止这种形式的跨源交互。
以上列表远非完整;其目标是突出工做中的“最小特权”原则。浏览器只公开应用程序代码所需的API和资源:应用程序提供数据和URL,浏览器格式化请求并处理每一个链接的完整生命周期。
值得注意的是,“同源策略”没有单一律念。相反,有一组相关机制强制限制DOM访问,Cookie和会话状态管理,网络以及浏览器的其余组件。
最好和最快的请求是未提出的请求。在分派请求以前,浏览器会自动检查其资源缓存,执行必要的验证检查,并在知足指定条件时返回资源的本地副本。若是本地资源在高速缓存中不可用,则会发出网络请求,而且响应会自动放入高速缓存中以供后续访问(若是容许)。
管理高效和优化的资源缓存很困难。值得庆幸的是,浏览器表明了咱们的整个复杂性,咱们须要作的是确保咱们的服务器返回适当的缓存指令;要了解更多信息,请参阅客户端上的缓存资源。您确实为网页上的全部资源提供了Cache-Control,ETag和Last-Modified响应标头,对吗?
最后,浏览器常常被忽视但关键的功能是提供身份验证,会话和cookie管理。浏览器为每一个来源维护单独的“Cookie JAR”,提供必要的应用程序和服务器API来读取和写入新的Cookie,会话和身份验证数据,并自动附加和处理相应的HTTP头以表明咱们自动执行整个过程。
一个例子:
将会话状态管理推迟到浏览器的便利性的一个简单但说明性示例:能够在多个选项卡或浏览器窗口之间共享通过身份验证的会话,反之亦然;单个选项卡中的注销操做将使全部其余打开的窗口中的打开会话失效。
走上提供网络服务的阶梯,咱们终于到达了应用程序API和协议。正如咱们所看到的,较低层提供了一系列关键服务:套接字和链接管理,请求和响应处理,各类安全策略的执行,缓存等等。每次咱们启动一个HTTP或一个XMLHttpRequest,一个长期服务器发送的事件或WebSocket会话,或打开一个WebRTC链接,咱们都与这些底层服务的一部分或所有进行交互。
没有单一的最佳协议或API。每一个非平凡的应用程序都须要根据各类需求混合使用不一样的传输:与浏览器缓存的交互,协议开销,消息延迟,可靠性,数据传输类型等等。某些协议可能提供低延迟传输(例如Server-Sent Events,WebSocket),但可能不符合其余关键条件,例如在全部状况下利用浏览器缓存或支持高效二进制传输的能力。