JavaScript 是如何工做的:深刻网络层 + 如何优化性能和安全

阿里云最近在作活动,低至2折,有兴趣能够看看:
https://promotion.aliyun.com/...

为了保证的可读性,本文采用意译而非直译。javascript

JavaScript 是如何工做的:深刻网络层 + 如何优化性能和安全html

这是专门探索 JavaScript 及其所构建的组件的系列文章的第 12 篇。前端

若是你错过了前面的章节,能够在这里找到它们:java

  1. JavaScript 是如何工做的:引擎,运行时和调用堆栈的概述!
  2. JavaScript 是如何工做的:深刻V8引擎&编写优化代码的5个技巧!
  3. JavaScript 是如何工做的:内存管理+如何处理4个常见的内存泄漏 !
  4. JavaScript 是如何工做的:事件循环和异步编程的崛起+ 5种使用 async/await 更好地编码方式!
  5. JavaScript 是如何工做的:深刻探索 websocket 和HTTP/2与SSE +如何选择正确的路径!
  6. JavaScript 是如何工做的:与 WebAssembly比较 及其使用场景 !
  7. JavaScript 是如何工做的:Web Workers的构建块+ 5个使用他们的场景!
  8. JavaScript 是如何工做的:Service Worker 的生命周期及使用场景!
  9. JavaScript 是如何工做的:Web 推送通知的机制!
  10. JavaScript是如何工做的:使用 MutationObserver 跟踪 DOM 的变化
  11. JavaScript是如何工做的:渲染引擎和优化其性能的技巧

正如在上一篇关于 渲染引擎 的博客文章中提到的,咱们认为优秀的 JavaScript 开发人员和杰出的 JavaScript 开发人员之间的区别在于,后者不只理解语言的具体细节,并且理解其内部结构和周遭环境。git

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!github

讲一点历史

49年前,一种叫作 ARPAnet 的网诞生了。它是一个早期的 分组交换网络,也是第一个 实现TCP/IP套件的网络。20年后,蒂姆·伯纳斯-李提出了一种“网状结构”的建议,这种结构后来被称为“万维网”。在这 49 年里,互联网走过了漫长的道路,从仅仅两台计算机交换数据包,到超过 7500 万台服务器、38 亿互联网用户和 13 亿个网站。web

"阿帕"(ARPA),是美国高级研究计划署(Advanced Research ProjectAgency)的简称。他的核心机构之一是信息处理(IPTO Information Processing Techniques Office),一直在关注电脑图形、网络通信、超级计算机等研究课题。

阿帕网为美国国防部高级研究计划署开发的世界上第一个运营的封包交换网络,它是全球互联网的始祖。chrome

图片描述

在这篇文章中,咱们将尝试分析现代浏览器使用什么技术来自动提升性能(甚至在你不知道的状况下),接着深刻浏览器网络层。最后,咱们将提供一些关于如何帮助浏览器提升 Web 应用程序性能的建议。编程

概览

现代 Web 浏览器专为快速,高效,安全地提供网络应用/网站而设计。 数百个组件在不一样的层上运行,从流程管理和安全沙箱到 GPU 管道,音频和视频等等,Web 浏览器看起来更像是一个操做系统,而不只仅是一个软件应用程序。segmentfault

浏览器的整体性能由许多大型组件决定:解析、布局、样式计算、JavaScript 和 WebAssembly 执行、渲染,固然还有网络堆栈。

工程师常常认为网络堆栈是一个瓶颈。这种状况常常发生,由于全部资源都须要从网上获取,而后才能解除其他步骤的阻塞。为了使网络层高效,它须要扮演的角色不只仅是一个简单的套接字管理器。它提供给咱们的是一种很是简单的资源获取机制,但实际上它是一个具备本身的优化标准、API 和服务的完整平台。

图片描述

做为 Web 开发人员,咱们没必要担忧单独的 TCP 或 UDP 数据包、请求格式化、缓存和其余一切问题。整个复杂性由浏览器负责,所以咱们能够将精力集中在咱们正在开发的应用程序上。然而,了解底层的状况能够帮助咱们建立更快、更安全的应用程序。

本质上,当用户开始与浏览器交互时会发生如下状况:

  • 用户在浏览器地址栏中输入一个 URL
  • 给定 Web 上资源的 URL,浏览器首先检查其本地缓存和应用程序缓存,并尝试使用本地副原本完成请求
  • 若是缓存不能使用,浏览器从 URL 获取域名,并从 DNS 请求服务器的 IP 地址。若是域被缓存,则不须要 DNS 查询
  • 浏览器建立一个 HTTP 包,表示它请求位于远程服务器上的 Web 页面
  • 数据包被发送到 TCP 层,TCP 层在 HTTP 数据包上添加本身的信息,维护已启动的会话须要此信息
  • 而后数据包被传递给 IP 层,IP 层的主要任务是找出一种将数据包从用户发送到远程服务器的方法,这些信息也存储在包的顶部
  • 数据包被发送到远程服务器
  • 一远程服务器一旦接收到数据包,就会以相似的方式发回响应。

W3C的浏览时序规范(Navigation Timing specification)提供了一个浏览器API,让咱们能够看到浏览器中每项请求的生命周期背后的时序和性能数据。让咱们看看这些组成部分,每一块都是影响最佳用户体验的关键点:

图片描述

整个网络过程很是复杂,有许多不一样的层,这可能成为瓶颈。这就是为何浏览器努力经过使用各类技术来提升本身的性能,从而使整个网络通讯的影响最小。

套接字管理

先了解一些术语:

  • 源(Origin) - 由应用程序协议,域名和端口号组成(例如https,www.example.com,443)
  • 套接字池(Socket pool) - 属于同一源的一组套接字(全部主要浏览器将最大池大小限制为6个套接字)

JavaScript 和 WebAssembly 不容许咱们管理单个网络套接字的生命周期,这是一件好事!这不只使咱们的省去较多麻烦,并且还可让浏览器自动进行许多性能优化,其中包括套接字重用、请求优先级和后期绑定、协议协商、强制链接限制等。

实际上,现代浏览器在将请求管理周期与套接字管理分离方面作了更多的工做。套接字组织在按源分组的池中,每一个池执行本身的链接限制和安全约束。挂起的请求被排队、排序,而后绑定到池中的各个套接字。除非服务器有意关闭链接,不然同一个套接字能够跨多个请求自动重用!

图片描述

因为打开新的 TCP 链接须要额外的成本,所以链接的重用自己就带来了巨大的性能优点。默认状况下,浏览器使用所谓的 “keepalive” 机制,它能够在发出请求时节省打开到服务器的新链接的时间。打开新 TCP 链接的平均时间为:

  • 当地的请求  — 23ms
  • 横贯大陆的请求 —— 120ms
  • 洲际请求 ——  225ms

这种架构为其余一些优化提供了可能, 请求能够根据其优先级以不一样的顺序执行。 浏览器能够优化全部套接字的带宽分配,也能够在预期请求时打开套接字。

正如以前提到的,这一切都由浏览器管理,不须要咱们作任何工做,但这并不意味着咱们什么都作不了。 选择正确的网络通讯模式,类型和传输频率,协议选择以及服务器堆栈的调优/优化能够在提升应用程序的总体性能方面发挥重要做用。

有些浏览器甚至更进了一步。 例如,Chrome 能够学习用户的操做习惯来使本身变得更快。 它根据访问的站点和典型的浏览模式进行学习,以便预测可能的用户行为并在用户执行任何操做以前采起措施。 最简单的例子是当用户在连接上悬停时,Chrome 会预先渲染页面, 若是有兴趣了解有关 Chrome 优化的更多信息,能够查看这篇文章 https://www.igvita.com/posa/h...

网络安全和沙盒

容许浏览器管理单个套接字还有另外一个很是重要的目的:经过这种方式,浏览器可以对不受信任的应用程序资源执行一致的安全和策略约束。例如,浏览器不容许 API 直接访问原始网络套接字,由于这将使任何恶意应用程序可以任意链接到任何主机。浏览器还强制执行链接限制,以保护服务器和客户端免于资源耗尽。

浏览器格式化全部传出请求,以强制执行一致且格式良好的协议语义,以保护服务器。相似地,响应解码是自动完成的,以保护用户免受恶意服务器的攻击。

TLS 协议

传输层安全性协议 (Transport Layer Security, TLS)是一种经过计算机网络提供通讯安全性的加密协议。它在许多应用程序中获得了普遍的应用,其中之一就是 Web 浏览器。网站可使用 TLS 保护服务器和Web 浏览器之间的全部通讯。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面。

整个TLS握手包括如下步骤:

  1. 客户端向服务器发送 “Client hello” 消息,与之一同发送的还有客户端产生的随机值和支持的密码套件。
  2. 服务器经过向客户端发送 “Server hello” 消息及服务器产生的随机值进行响应。
  3. 服务器将其证书发送给客户端,并能够从客户端请求相似的证书。 服务器发送 “Server hello done” 消息。
  4. 若是服务器向客户机请求了证书,客户机将发送证书。
  5. 客户端建立一个随机的 Pre-Master Secret,并使用服务器证书中的公钥对其进行加密,将加密的 Pre-Master Secret 发送到服务器。
  6. 服务器接收 Pre-Master Secret。 服务器和客户端均基于预主密钥生成主密钥和会话密钥。
  7. 客户端向服务器发送 “Change cipher spec” 通知,以指示客户端将开始使用新的会话密钥进行散列和加密消息。 客户端还发送 “Server finished” 消息。
  8. 服务器接收 “Change cipher spec”,并使用会话密钥将其记录层安全状态切换为对称加密。 服务器向客户端发送 “Server finished” 消息。
  9. 客户端和服务器如今能够经过他们已创建的安全通道交换应用程序数据。 从客户端发送到服务器并返回的全部消息都使用会话密钥加密。

若是任何验证失败,则警告用户 - 例如,服务器正在使用自签名证书。

同源策略(same-origin policy)

同源是指文档的来源相同,主要包括三个方面

  • 协议
  • 主机
  • 载入文档的 URL 端口

如下是一些可能嵌入跨源资源的一些例子:

  • 带有 <script src =“...”> </ script> 的 JavaScript。 语法错误的错误消息仅适用于同源脚本
  • 带有 <link rel =“stylesheet”href =“...”> 的CSS。 因为 CSS 的宽松语法规则,跨源 CSS 须要正确的 Content-Type 标头。不一样浏览器可能有不一样的限制
  • 经过 <img> 加载图片
  • 带有 <video><audio> 的媒体文件
  • 带有 <object><embed><applet> 的插件
  • @font-face 的字体。 某些浏览器容许跨源字体,其余浏览器须要同源字体
  • 任何有 <frame><iframe> 的东西。 站点可使用 X-Frame-Options 头部标识来阻止这种形式的跨源交互

以上列表并不是完整,其目的是强调工做中 “最小特权” 的原则。 浏览器仅公开应用程序代码所需的 API 和资源:应用程序提供数据和 URL,浏览器格式化请求并处理每一个链接的整个生命周期。

值得注意的是,“同源策略”并非一个单一律念。相反,有一组相关的机制来限制对 DOM 访问、cookie 和会话状态管理、网络和浏览器的其余组件。

资源和客户端状态缓存

最佳请求是没有从新请求。在发送请求以前,浏览器会自动检查其资源缓存,执行必要的验证检查,并在知足指定条件的状况下返回资源的本地副本。若是缓存中没有可用的本地资源,则发出网络请求,并自动将响应放置在缓存中,以便在有权限的状况下进行后续访问。

  • 浏览器自动评估每一个资源上的缓存指令
  • 浏览器会尽量自动从新验证过时资源
  • 浏览器自动管理缓存大小和资源回收

管理高效且优化的资源缓存很难。 值得庆幸的是,浏览器帮咱们处理整个复琐事情,咱们须要作的就是确保咱们的服务器返回适当的缓存指令; 要了解更多信息,请参阅 客户端的缓存资源(Cache Resources on the Client)。 这个须要咱们为页面上的全部资源提供了 Cache-ControlETag Last-Modified 响应头部标志。

最后,浏览器的一个常常被忽视的关键功能是提供身份验证、会话和 cookie 管理。浏览器为每一个源维护独立的 “cookie jars”,提供必要的应用程序和服务器 Api 来读写新的 cookie、会话和身份验证数据,并自动附加上和处理相应的 HTTP 头以代替咱们自动执行整个过程。

来个例子:

用一个简单但有说明性的例子来讲明将会话状态管理推放到浏览器端的便利之处:同一个通过身份验证的会话能够在多个选项卡或浏览器窗口之间共享,反之亦然;单个选项卡中的注销操做将使全部其余打开的窗口中打开的会话失效。

应用程序 Api 和协议

研究完了网络服务,终于到达了应用程序 API 和协议这一步。正如咱们所看到的,底层提供了大量关键服务:套接字和链接管理、请求和响应处理、各类安全策略的执行、缓存等等。每当咱们启动 HTTP 或 XMLHttpRequest 、长期的 Server-Sent Events 或 WebSocket 会话,或打开 WebRTC 链接时,咱们都在与这些底层服务进行交互。

没有单一的最佳协议或 API。 每一个稍微复杂的应用程序都须要根据各类要求混合使用不一样的传输:与浏览器缓存的交互,协议开销,消息延迟,可靠性,数据传输类型等。 某些协议可能提供低延迟传送(例如,Server-Sent Events,WebSocket),但可能不符合其余关键标准,例如在全部状况下利用浏览器缓存或支持有效二进制传输的能力。

如下是一些来提升 Web 应用程序的性能和安全性技巧

  • 始终在请求中使用 “Connection: Keep-Alive” 头部标识,浏览器默认执行此操做,确保服务器使用相同的机制。
  • 使用正确的 Cache-Control,Etag 和 Last-Modified 头部标识,这样就能够节省浏览器的下载时间。
  • 花时间调整和优化你的 Web 服务器,这是才是真正的最有效的地方! 请记住,该过程要针对每一个 Web 应用程序以及你要传输的数据的类型要更加具体考虑和处理。
  • 始终使用TLS,特别是若是你的应用程序中有任何类型的身份验证。
  • 研究浏览器在你的应用程序中提供和实施的安全策略。


原文:

https://blog.sessionstack.com...

个人博客即将同步至腾讯云+社区,邀请你们一同入驻:https://cloud.tencent.com/dev...

你的点赞是我持续分享好东西的动力,欢迎点赞!

交流

干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,便可看到福利,你懂的。

clipboard.png

相关文章
相关标签/搜索