关于javascript:从输入URL到渲染的过程中到底发生了什么

43次阅读

共计 8725 个字符,预计需要花费 22 分钟才能阅读完成。

  • CDN
  • 缓存
  • DNS
  • TCP 三次握手、四次挥手
  • 浏览器渲染过程
  • 输出 URL 到页面渲染过程的一些优化

上面我将“从输出 URL 到渲染的全过程”大略的形容进去,再对其过程加以解释,理解过程中能够做哪些优化。文章内容有点长,须要有足够的急躁看完哟!!上面我要开始啦!

1、URL 解析

2、DNS 解析

3、建设 TCP 链接

4、客户端发送申请

5、服务器解决和响应申请

6、浏览器解析并渲染响应内容

7、TCP 四次挥手断开连接

一、URL 解析

地址解析和编码

咱们输出 URL 后,浏览器会解析输出的字符串,判断是 URL 还是搜寻关键字,如果是 URL 就开始编码。
一般来说 URL 只能应用英文字母、阿拉伯数字和某些标点符号,不能应用其余文字和符号,所以,如果 URL 中有文字就必须编码后应用。然而 URL 编码很凌乱,不同的操作系统、浏览器、网页字符集,会导致不同的编码后果。所以咱们须要应用 JavaScript 先对 URL 编码,而后提交给服务器,不给浏览器插手的机会。咱们通常会应用 encodeURI()函数或者 encodeURIComponent()函数来编码 URL

HSTS

HSTS(HTTP Strict TransportSecurity)是一种新的 Web 平安协定,HSTS 的作用是强制客户端应用 HTTPS 与服务器创立连贯。比方你在地址栏输出 http://xxx/,浏览器会主动将 http 转写成 https,而后间接向 https://xxx/ 发送申请。

缓存查看

浏览器在发送申请之前先查看有没有缓存,过程如下:

浏览器会先去查看强缓存(Expires 和 cache-control)判断是否过期,如果强缓存失效,间接从缓存中读取资源;若不失效则进行协商缓存(Last-Modified / If-Modified-Since 和 Etag/If-None-Match),协商缓存由服务器决定是否应用缓存,若协商缓存生效,那么代表该申请的缓存生效,返回 200,并从新返回资源和缓存标识,再次存入浏览器缓存中;失效则返回 304,并从缓存中读取资源。(协商缓存之前要通过 DNS 域名解析,之后建设 TCP 链接)

那么浏览器缓存的地位在哪呢?

  • Service Worker:浏览器独立线程进行缓存
  • Memory Cache:内存缓存
  • Disk Cache:硬盘缓存
  • Push Cache:推送缓存(HTTP/ 2 中的)

留神 :输出网址之后,会查找内存缓存,没有再找硬盘,都没有就产生网络申请。
一般刷新(F5):因为 TAB 没有敞开,所以内存缓存可用,如果匹配上会被优先应用,其次是磁盘缓存
强制刷新(Ctrl+F5):浏览器不应用缓存,因而发送的申请头均带有 Cache-control:no-cache, 服务器间接返回 200 和最新内容。

二、进行 DNS 解析

DNS

(1)、DNS:把域名和 ip 地址互相映射分布式数据库,让用户能更不便的拜访互联网,DNS 协定运行在 UDP 协定之上
(2)、DNS 解析:通过域名最终失去对应 ip 地址的过程。
(3)、DNS 缓存:浏览器,操作系统,路由器,本地 DNS,根域名服务器都会对 DNS 后果作出肯定的缓存

DNS 解析过程

(1)、首先搜寻浏览器本身的 DNS 缓存,有缓存间接返回;
(2)、浏览器本身 DNS 不存在,浏览器就会调用一个相似 gethostbyname 的库函数, 此函数会先去检测本地 hosts 文件,查看是否有对应 ip。
(3)、如果本地 hosts 文件不存在映射关系,就会查问路由缓存,路由缓存不存在就去查找本地 DNS 服务器(个别 TCP/IP 参数里会设首选 DNS 服务器,通常是 8.8.8.8)(客户端到本地 DNS 服务器是递归过程)
(4)、如果本地 DNS 服务器还没找到就会向根服务器发出请求。(DNS 服务器之间是迭代过程)
具体过程:

  • 本地 DNS 服务器代咱们的浏览器发动迭代 DNS 解析申请,首先它会找根域的 DNS 的 IP 地址(寰球 13 台哟,惋惜中国没有!)。找到根域的 DNS 地址, 就会向其发动申请(请问 www.baidu.com 这个域名的 IP 地址是多少呀?);
  • 根域发现这是一个顶级域 com 域的一个域名,于是通知本地 DNS 服务器我不晓得这个域名的 IP 地址, 然而我晓得 com 域的 IP 地址,你去找它去吧;
  • 于是本地 DNS 服务器就失去了 com 域的 IP 地址,又向 com 域的 IP 地址发动了申请(请问 www.baidu.com 这个域名的 IP 地址是多少呀?), 于是 com 域服务器通知本地 DNS 服务器我不晓得 www.baidu.com 这个域名的 IP 地址,然而我晓得 baidu.com 这个域的 DNS 地址,你去找它去;
  • 于是本地 DNS 服务器又向 baidu.com 这个域名的 DNS 地址(这个个别就是由域名注册商提供的,像万网,新网等)发动申请(请问 www.baidu.com 这个域名的 IP 地址是多少?),这个时候 baidu.com 域的 DNS 服务器一查,呀!果然在我这耶,于是就把找到的后果发送给本地 DNS 服务器;
  • 这个时候本地 DNS 服务器就拿到了 www.baidu.com 这个域名对应的 IP 地址。

DNS 优化

DNS 也是开销,通常浏览器查找一个给定域名的 IP 地址要花费 20~120 毫秒,在实现域名解析之前,浏览器不能从服务器加载到任何货色。那么如何缩小域名解析工夫,放慢页面加载速度呢?

(1)、缩小 DNS 申请次数
(2)、DNS 预获取,DOM 还没开始,浏览器预解析地址,把解析好的地址放在本地缓存外面,DOM 树生成完,要加载图片类的发现 DNS 曾经解析好了,再发送申请。<link rel=’dns-prefetch’href=’//dfns.tanx.com’>
(次要对图片资源)
(3)、DNS 查问的过程经验了很多的步骤,如果每次都如此,会消耗太多的工夫、资源。所以咱们应该尽早的返回实在的 IP 地址:(缩小查问过程,也就是 DNS 缓存。浏览器获取到 IP 地址后,个别都会缓存到浏览器的缓存中,本地的 DNS 缓存服务器,也能够去记录。另外,每天几亿网名的拜访需要,一秒钟几千万的申请域名服务器如何满足?就是 DNS 负载平衡。通常咱们的网站利用各种云服务,或者各种服务商提供相似的服务,由他们去帮咱们解决这些问题。DNS 零碎依据每台机器的负载量,地理位置的限度(长距离的传输效率)等等,去提供高效疾速的 DNS 解析服务。
(4)、当客户端 DNS 缓存(浏览器和操作系统)缓存为空时,DNS 查找的数量与要加载的 Web 页面中惟一主机名的数量雷同,包含页面 URL、脚本、样式表、图片、Flash 对象等的主机名。缩小主机名的数量就能够缩小 DNS 查找的数量;
(5)、缩小惟一主机名的数量会潜在缩小页面中并行下载的数量(HTTP1.1 标准倡议从每个主机名并行下载两个组件,但实际上能够多个);然而缩小主机名和并行下载的计划会产生矛盾,须要大家本人衡量。倡议将组件放到至多两个但不多于 4 个主机名下,缩小 DNS 查找的同时也容许高度并行下载。

DNS 解析后会把域名的解析权交给 cname()指向的内容散发(CDN)专用的 DNS 服务器。CDN 专用的 DNS 服务器把 CDN 的全局负载平衡设施的 ip 地址返回给用户

参考 前端进阶面试题具体解答

CDN

举个例子:以前坐火车买票,都要到火车站买,所有人都去火车站买票,火车站售票厅的压力可想而知有多大。
起初火车票代售点呈现了,散布在各个城市,城镇,咱们只须要去间隔咱们最近的火车票售卖点买票就能够了。
卖火车票的代理售票点(缓存服务器),为买票者提供了不便,帮忙他们在最近的中央(最近的 CDN 节点),
用最短的工夫(最短的申请工夫)买到票(拿到资源)。加重了售票大厅的压力(起到分流作用,加重服务器负载压力)

CDN 缓存:

在浏览器本地缓存生效后,浏览器会像 CDN 边缘节点发动申请,相似浏览器缓存,CDN 边缘节点也存在一套缓存机制,

  • CDN 边缘节点缓存策略因服务商不同而不同,通过 http 响应头中的 cache-control:max-age 字段设置 CDN 边缘节点数据缓存工夫。
  • 当浏览器向 CDN 节点申请数据时,CDN 节点会判断缓存数据是否过期,若缓存数据过期,CDN 会向服务器收回回源申请,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端,CDN 服务商个别会提供基于文件后缀,目录多个维度来指定 CDN 缓存工夫,为用户提供更精细化的缓存治理。

CDN 工作形式:

(1)、当你点击网站页面的 url 时,通过本 DNS 解析,DNS 解析后会把域名的解析权交给 cname()指向的内容散发专用的 DNS 服务器。内容散发专用的 DNS 服务器把内容散发的全局负载平衡(GSLB)设施的 ip 地址返回给用户。
(2)、当你向 CDN 的全局负载平衡设施的 ip 地址发动 url 拜访申请,CDN 的全局负载平衡设施会为你抉择一台适合的缓存服务器提供服务。

  • 抉择的根据:用户的 ip 地址,判断哪台服务器间隔用户最近,依据用户申请的 url 中携带的内容名称判断哪台服务器上有用户要的数据,查问各个服务器以后负载状况,判断哪台服务器有服务能力。
  • 调配:基于这些条件综合剖析后,区域负载平衡设施会向全局负载平衡设施申请返回一台缓存服务器的 IP 地址。全局负载平衡设施返回服务器 IP 地址,用户向缓存服务器发动申请,缓存服务器响应用户申请,将用户所需内容传送到用户终端,如果这台缓存服务器没有用户想要的内容,而区域平衡设施仍然将它调配给了用户,那么这台服务器就要向它的上一级缓存服务器申请内容,直至追溯到网站的源服务器将内容拉到本地。域名解析服务器依据用户 ip 地址,把域名解析成相应节点的缓存服务器 ip 地址,实现用户就近拜访,应用 CDN 服务的网站,只有将其域名解析权交给 CDN 的全局负载平衡设施,将须要散发的内容注入到 CDN 就能够实现内容减速了。

CDN 劣势:

(1)、CDN 节点解决了跨运营商和跨地区拜访的问题,拜访延时大大降低;
(2)、大部分申请在 CDN 边缘节点实现,CDN 起到分流作用,加重了源服务器的负载。

CDN 劣势

(1)、当网站更新时,如果 CDN 节点上数据没有及时更新,即使用户在浏览器应用 Ctrl +F5 的形式使浏览器端的缓存生效,也会因为 CDN 边缘节点没有同步最新数据而导致用户拜访异样。
(2)、CDN 不同的缓存工夫会对“回源率”产生间接的影响:

  • 如果缓存工夫短,CDN 边缘节点的内容常常生效,导致频繁回源。不仅减少服务器压力,也减少了用户拜访工夫。
  • 如果缓存工夫长,数据更新了,边缘节点的内容都还没更新,开发者对特定的工作做特定的数据缓存工夫治理。

CDN 刷新缓存

CDN 边缘节点对开发者是通明的,相比于浏览器 Ctrl+F5 的强制刷新来使浏览器本地缓存生效,开发者能够通过 CDN 服务商提供的“刷新缓存”接口来达到清理 CDN 边缘节点缓存的目标。这样开发者在更新数据后,能够应用“刷新缓存”性能来强制 CDN 节点上的数据缓存过期,保障客户端在拜访时,拉取到最新的数据。|

CDN 优化

(1)、前端须要被减速的文件大抵包含:

js、css、图片、视频、和页面等文件。页面文件有动静和动态之分。这些文件和页面(比方 html)最大的区别是:这些文件都是动态的,改变比拟小,这类动态文件适宜做 CDN 减速。咱们把这些动态文件通过 CDN 散发到世界各地的节点,用户能够在间隔最近的边缘节点拿到须要的内容,从而晋升内容下载速度放慢网页关上速度。页面分为动静页面和动态页面,动静页面不适宜做 CDN 缓存,因为页面是动静的话,内容的有效期就比拟沉闷。边缘节点的数据常常生效要回源,造成源服务器压力。

(2)、缩小资源申请的等待时间

不同浏览器的并发数量不一样:IE11、IE10、chrome、Firefox 的并发连接数是 6 个,IE9 是 10 个。如果页面动态资源(图片等)过多(大于 6 个)会存在资源申请期待的状况。目前现实状况是大多用户带宽越来越大,然而咱们的动态资源并非那么大,很多文件都是几 k 或者几十 k,6 个文件加起来都小于带宽。这样就导致了资源的节约。

  • 解决方案是:用多个不同 IP 的服务器来存储这些文件,并在页面中通过绝对路径的形式援用(要求同一 IP 的文件不超过 6 个)。这样就能够尽可能的缩小资源申请期待的状况。

至此,你曾经获取到缓存服务器的 IP 地址,并且筹备向这个 IP 地址发送申请了。

三、建设 TCP 连贯

TCP

(1)、TCP 是一种面向连贯的,牢靠的,基于字节流的传输层通信协议。
(2)、建设 TCP 连贯须要进行三次握手。过程如下:

TCP 握手过程

(1)、客户端发送带有 SYN 标识(SYN=1,seq=x)的申请报文段,而后进入 SYN_SEND 状态,期待服务端确认;
(2)、服务端接管到客户端 SYN 报文段后,须要发送 ACK 信息对这个 SYN 进行确认,同时还要发送本人的 SYN 信息(SYN=1,ACK=1,seq=y,ack=x+1)服务端把这些信息放在一个报文段中((SYN+ACK 报文段),一并发给客户端,此时客户端进入 SYN_RECV 状态;
(3)、客户端接管到服务端的 SYN+ACK 报文段后会向服务端发送 ACK(ACK=1,seq=x+,ack=y+1)确认报文段,这个报文段发送后,客户端和服务端都进入 ESTABLISHED 状态,实现三次握手。

为什么 TCP 建设肯定要三次呢?两次不行吗?

起因

  • 单方要明确对方接管能力都是失常的,(客户端发之后,服务端能够确定客户端发送能力失常,服务端发送给客户端,客户端能够确定服务端的接管和发送能力失常,最初客户端发送确认,来确定客户端的接管能力。
  • 为了避免已生效的连贯申请报文段忽然又传送到了服务端,因此产生谬误”。

四、客户端发送申请

TCP 三次握手建设连贯胜利后,客户端依照指定的格局开始向服务端发送 HTTP 申请。

申请过程优化

缩小 HTTP 申请次数和申请资源大小

(1)、资源合并压缩
(2)、字体图标(精灵图根本不是好的优化形式了,不好保护)
(3)、base64
(4)、Gzip(个别文件能压缩 60%)
(5)、图片懒加载
(6)、数据提早分批加载
(7)、CDN 资源

五、服务器响应申请

服务器端收到申请后由 web 服务器(精确说应该是 http 服务器)解决申请,诸如 Apache、Ngnix、IIS 等。web 服务器解析用户申请,理解了要调度哪些资源文件,再通过响应的资源文件解决用户申请和参数,并调用数据库信息,最初将后果通过 web 服务器返回给浏览器客户端。

六、断开连接

服务器响应完客户端申请之后,解除 TCP 连贯,开释过程(四次挥手过程)如下:

(1)、客户端发送标记为 FIN=1(finished 的缩写,示意接管实现,申请开释连贯),同时生成一个 Seq= u 的序列号,之后进入 FIN-WAIT- 1 半敞开阶段(此时客户端到服务端发送数据的通道曾经敞开,然而依然能够接管服务端发过来的数据);
(2)服务器收到连贯开释报文,收回确认报文,ACK=1,ack=u+1,并且带上本人的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT(敞开期待)状态。TCP 服务器告诉高层的利用过程,客户端向服务器的方向就开释了,这时候处于半敞开状态,即客户端曾经没有数据要发送了,然而服务器若发送数据,客户端仍然要承受。这个状态还要继续一段时间,也就是整个 CLOSE-WAIT 状态继续的工夫。
(3)客户端收到服务器的确认申请后,此时,客户端就进入 FIN-WAIT-2(终止期待 2)状态,期待服务器发送连贯开释报文(在这之前还须要承受服务器发送的最初的数据)。
(4)服务器将最初的数据发送结束后,就向客户端发送连贯开释报文,FIN=1,ack=u+1,因为在半敞开状态,服务器很可能又发送了一些数据,假设此时的序列号为 seq=w,此时,服务器就进入了 LAST-ACK(最初确认)状态,期待客户端的确认。
(5)客户端收到服务器的连贯开释报文后,必须收回确认,ACK=1,ack=w+1,而本人的序列号是 seq=u+1,此时,客户端就进入了 TIME-WAIT(工夫期待)状态。
(6)服务器只有收到了客户端收回的确认,立刻进入 CLOSED 状态,就完结了这次的 TCP 连贯。

为什么要四次握手而不是三次、两次

因为建设一旦连贯,单方既是发送方,又是接管方,为了保障在最初断开的时候,客户端发送的最初一个 ACK 报文段可能被服务器接管到。如果客户端在收到服务器给它的断开连接的申请之后,回应完服务器就间接断开连接的话,服务器就会因为始终没失去客户端响应而始终期待,所以客户端要期待两个最长报文段寿命的工夫,以便于服务器没有收到申请之后从新发送申请。

七、浏览器解析并渲染响应内容

在这之前咱们先来补充一点基础知识:

浏览器的渲染引擎组成(列举的是根本组成)

(1)、HTML 解析器: 将 HTML 解析成 DOM 树。
(2)、CSS 解析器: 为 DOM 中各个元素对象计算出款式信息,为布局提供基础设施。
(3)、JavaScript 引擎: 解析并执行 javascript 代码。
(4)、布局 layout 模块: 在 DOM 树创立后,webkit 须要将其中的元素对象同样式信息联合起来,计算他们的大小地位等布局信息,造成一个能表白这所有信息的模型。
(5)、绘图模块: 应用图形库将布局计算后的各个网页的节点绘制成图像的后果。

渲染过程

(1)、浏览器拿到文件后(拿到的是一些字节码)通过编码方式(个别是 utf-8)转换为对应的字符。
(2)、浏览器至上而下解析文档,遇见 HTML 标记,调用 HTML 解析器解析为对应的 tocken,tocken 就是标签文本的序列号,将 tocken 按词法解析解析成具体的标记构造,这个过程曾经构建出一颗有标签,有层级,有构造的 DOM 树(就是一块内存,这块内存理论就是一个个 Tocken 形成的);
(3)、遇见 style/link 标记,调用 CSS 解析器解决 CSS 标记并构建 CSSOM 款式树;
(4)、遇见 script 标记,调用 javascript 解析器解决,绑定事件、批改 DOM 树 /CSS 树等;
(5)、将 DOM 树和 CSSOM 树合并成一颗 render 树(渲染树)。
(6)、依据渲染树来渲染,计算每个节点的几何信息(这一过程要依赖图形库);
(7)、将各个节点绘制到屏幕上。
如果用户操作页面,会触发第(6)或者第(7)步骤,也就是重排和重绘

阻塞渲染

(1)、style 标签的款式:

  • 由 HTML 解析器解析(异步解析);
  • 不阻塞浏览器渲染(可能会呈现闪屏(解析一点,显示一点景象);
  • 不阻塞 DOM 解析。

(2)、link 引入的内部 css 款式(举荐应用)

  • 由 CSS 解析器解析(同步解析);
  • 阻塞浏览器渲染(能够利用这种阻塞防止闪屏);
  • 阻塞其后 js 语句的执行:
    起因:如果前面 js 的内容是获取元素的款式,例如宽低等属性, 如果不等款式解析结束,前面的 js 就取得了谬误的信息, 因为浏览器也不晓得后续 js 的具体内容,所以只好等后面所有款式解析结束,再执行 js。例如:firefox 在款式加载和解析过程,会禁止所有脚本。(webkit 内核的浏览器只会在 js 尝试拜访款式属性或者可能受到未加载的款式影响时才会禁止脚本。
  • 不阻塞 DOM 的解析:
    起因:DOM 解析和 CSS 解析是两个并行的线程。

(3)、优化外围概念:尽可能快的进步内部 css 加载速度。

  • 应用 CDN 节点进行内部资源打包;
  • 对 css 进行压缩(利用打包工具,比方 webpack,glup 等;
  • 缩小对 http 申请数量,将多个 css 文件合并;
  • 优化款式的代码。

(4)、js 阻塞:

  • 阻塞 DOM 解析:
    起因:浏览器不晓得后续脚本的内容,如果先去解析了上面的 DOM,而随后 js 删除了前面的所有 DOM,做了无用功。浏览器无奈预估脚本具体做了什么操作,索性全副暂停,等脚本执行完,浏览器再持续向下解析。
  • 阻塞页面的渲染:
    起因:js 中也能够给 DOM 设置款式,浏览器同样等该脚本执行完再持续干活,防止做无用功。
  • 阻塞后续 js 的执行:
    起因:保护依赖关系,例如:必须先引入 jQuery 再引入 bootstrap。
  • 如果 script 脚本加了 defer:浏览器会发送申请加载 js,然而不会阻塞 DOM 解析,等 DOM 解析完,再执行 js。
  • 如果 script 加了 async:浏览器会发送申请加载 js,不阻塞 DOM 解析,等 js 加载过去了,就先进行 DOM 解析,去执行 js(谁先回来先执行谁),等 js 执行完,持续 DOM 解析。

渲染过程优化

(1)、标签语义化(应用适合的标签,如果不是 w3c 规定的标签,Tocken 令牌和词法解析语法得辨认剖析,是不是 wc3 规定的)
(2)、缩小标签嵌套(生成构造树嵌套太多,就得递归(在 DOM 树构建时候快能够一点)
(3)、款式尽可能少的层级嵌套(应用与编译器的时候,层级嵌套要慎用。CSS 选择器渲染从右到左,.box a{}会 比 a{} 慢
(4)、尽早把 CSS 下载到客户端(充分利用 HTTP 多申请并发机制)
(5)防止阻塞 js 放在底部
(6)、缩小回流

  • 放弃传统操作 DOM 时代,基于 vue/react 开始数据影响试图模式
  • 款式集中扭转
  • 缓存布局信息,
  • 动画成果利用到 position 属性为 absolute 或 fixed 的元素上(脱离文档流)
  • CSS3 硬件加速(比起思考如何缩小回流重绘,更冀望不要回流重绘:transform、opacity、filters 这些属性会触发硬件加速,不会引发回流重绘(过多应用占用大量内存,性能耗费重大
  • 防止应用 table 布局和应用 css 的 js 表达式

结语

通过浏览本文,置信小伙伴们对从输出 URL 到页面渲染的过程有了一个大略的了解。其实整个过程是很简单也比拟繁琐的,不是一篇文章或者几张图就能够囊括的,在这有很多细节不便开展,有趣味的小伙伴能够对这个过程中的一些细节深入研究钻研哦!文章中必定会有些说的不是很分明的中央,恳请各位大佬不吝赐教,一起成长!

正文完
 0