天天看点

从输入URL到页面加载发生了什么?

从输入url到页面加载发生了什么

url解析:地址栏网址缓存

检查hsts 预加载列表

dns查询: dns 缓存 一个网址到ip地址的转换,这个过程就是dns解析

arp(地址解析协议)缓存

tcp 连接: tcp 发送缓冲区 & 接收缓冲区

处理请求: http请求缓存( cdn 节点缓存、代理服务器缓存、浏览器缓存、后端动态计算结果缓存等 )

接受响应,渲染页面

根据用户的输入url后遇到的第一个缓存环节就是地址栏网址缓存,我们只是输入了几个字母,浏览器就自动补全了该网址。当我们使用这个自动补全的网址时,你会发现请求的相关的静态资源也是从缓存中取得的

不论什么时候,我们获取的主页面资源 timeline, 都应该是重新请求服务器而获得的,不可以使用本地浏览器的缓存。至于为什么?你看到静态资源文件名的 hash 值你就应该清楚了

转换非 ascii 的 unicode 字符

浏览器检查输入是否含有不是 a-z,a-z,0-9,- 或者 . 的字符;如果有的话,浏览器会对主机名部分使用 punycode 编码

hsts:http严格传输安全(http strict transport security )国际互联网工程组织 iete 正在推行一种新的web安全协议,作用是强制客户端(如浏览器)使用 https 与服务器创建连接。

采用hsts后:hsts 支持这个协议的浏览器,在输入url后会检查自带的hsts预加载列表(这个列表里包含了那些请求浏览器只使用https进行连接的域名),若网站在这个列表里,浏览器会使用https协议并且返回码为 307。而不支持hsts的浏览器访问我们的网站,则不会产生跳转,从而提高了兼容性。 如掘金输入 http://juejin.im/timeline 会跳转到 https://juejin.im/timeline:

浏览器还会进行一些额外的操作,比如安全检查、访问限制(之前国产浏览器限制 996.icu)

dns解析的过程就是寻找哪台机器上有你需要资源的过程,也是一个获取目标域名ip的过程。

基于域名到ip的查找过程太耗时间,步骤也多。所以需要对dns做优化。dns存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,ips服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存
浏览器搜索自己的 dns 缓存(浏览器维护一张域名与 ip 地址的对应表);如果没有命中,进入下一步;搜索操作系统中的 dns 缓存;如果没有命中,进入下一步;搜索操作系统的 hosts 文件( windows 环境下,维护一张域名与 ip 地址的对应表);如果没有命中,进入下一步

在你的chrome浏览器中输入:chrome://dns/,你可以看到chrome浏览器的dns缓存。

系统缓存主要存在/etc/hosts(linux系统)中:

虽然 dns 缓存可以提高获取 dns 的速度,但缓存时间过长也会影响 dns 在 ip 变更时不能及时解析到最新的ip;所以浏览器dns缓存不会太长,一分钟左右左右

操作系统将域名发送至 ldns (本地区域名服务器),ldns 查询自己的 dns 缓存(一般命中率在 80% 左右),查找成功则返回结果,失败则发起一个迭代 dns 解析请求:

ldns向 root name server(根域名服务器,如com、net、im 等的顶级域名服务器的地址)发起请求,此处,root name server 返回 im 域的顶级域名服务器的地址;

ldns 向 im 域的顶级域名服务器发起请求,返回 juejin.im 域名服务器地址;

ldns 向 juejin.im 域名服务器发起请求,得到 juejin.im 的 ip 地址;

ldns 将得到的 ip 地址返回给操作系统,同时自己也将 ip 地址缓存起来;操作系统将 ip 地址返回给浏览器,同时自己也将 ip 地址缓存起来。

默认情况下浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的 dns prefetch;在前端优化中与 dns 有关的有两点

减少 dns 的请求次数

进行 dns 预获取

dns prefetch 应该尽量的放在网页的前面,推荐放在  后面。具体使用方法如下:

如果需要禁止隐式的 dns prefetch,可以使用以下的标签:

大家耳熟能详的cdn(content delivery network)就是利用dns的重定向技术,dns服务器会返回一个跟用户最接近的点的ip地址给用户,cdn节点的服务器负责响应用户的请求,提供所需的内容。

arp 是一种用以解释地址的协议,根据通信方的 ip 地址就可以反查出对应方的 mac 地址。

arp 缓存是个用来储存 ip 地址和 mac 地址的缓冲区,其本质就是一个 ip 地址与 mac 地址的对应表,表中每一个条目分别记录了其他主机的 ip 地址和对应的 mac 地址。
当地址解析协议被询问一个已知 ip 地址节点的 mac 地址时,先在 ar 缓存中查看,若存在,就直接返回与之对应的mac地址;若不存在,才发送 arp 请求查询

http协议是使用tcp作为其传输层协议的;tcp创建过程和链接折除过程是由tcp/ip协议栈自动创建的

tcp报文格式

1)序号:seq序号,占32位,用来标识从tcp源端向目的端发送的字节流,发起方发送数据时对此进行标记。

2)确认序号:ack序号,占32位,只有ack标志位为1时,确认序号字段才有效,ack=seq+1。

3)标志位:共6个,即urg、ack、psh、rst、syn、fin等,具体含义如下:(a)urg:紧急指针(urgent pointer)有效。(b)ack:确认序号有效。(c)psh:接收方应该尽快将这个报文交给应用层。(d)rst:重置连接。(e)syn:发起一个新连接。(f)fin:释放一个连接。

tcp三次握手建立一个tcp连接时,需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立tcp连接,并同步连接双方的序列号和确认号并交换

tcp 四次挥手:tcp的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作

发送http请求的过程就是构建http请求报文并通过tcp协议中发送到服务器指定端口(http协议80/8080, https协议443)。http请求报文是由三部分组成: 请求行, 请求报头和请求正文。

https过程: https在传输数据之前需要客户端与服务器进行一个握手(tls/ssl握手),在握手过程中将确立双方加密传输数据的密码信息,tls/ssl使用了非对称加密,对称加密以及hash等

http 请求缓存( cdn 节点缓存、代理服务器缓存、浏览器缓存、后端动态计算结果缓存等 )

当客户端再次请求该资源的时候,会在其请求头上附带上 if-modified-since 字段(值就是第一次获取请求资源时响应头中返回的 last-modified 值)

当客户端再次请求该资源的时候,会在其请求头上附带上 if-none-match 字段(值就是第一次获取请求资源时响应头中返回的 etag 值)

cache-control 的优先级会更高一点

请求头:no-cache no-store

响应头:no-cache no-store public

强缓存 ( cache-control 和 expires )强缓存主要是采用响应头中的 cache-control 和 expires 两个字段进行控制的。可用在请求头和响应头

协商缓存 ( last-modified 和 etag )

状态码

1xx:指示信息–表示请求已接收,继续处理。

2xx:成功–表示请求已被成功接收、理解、接受。

3xx:重定向–要完成请求必须进行更进一步的操作。

4xx:客户端错误–请求有语法错误或请求无法实现。

5xx:服务器端错误–服务器未能实现合法的请求。

平时遇到比较常见的状态码有:200, 204, 301(永久重定向), 302(临时重定向), 304(缓存), 400, 401, 403, 404, 422, 502(网关)

dom tree:浏览器将html解析成树形的数据结构。(https://segmentfault.com/a/1190000014520786)

css rule tree:浏览器将css解析成树形的数据结构。

render tree: dom和cssom合并后生成render tree。

layout: 布局;有了render tree,浏览器已经能知道网页中有哪些节点、各个节点的css定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。

painting:绘制; 按照算出来的规则,通过显卡,把内容画到屏幕上。

composite(渲染层合并)对页面中 dom 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常

某些特殊的渲染层会被认为是合成层(compositing layers),合成层拥有单独的 graphicslayer,而其他不是合成层的渲染层,则和其第一个拥有 graphicslayer 父层公用一个

每个 graphicslayer 都有一个 graphicscontext,graphicscontext 会负责输出该层的位图,位图是存储在共享内存中,作为纹理上传到 gpu 中,最后由 gpu 将多个位图进行合成,然后 draw 到屏幕上,此时,我们的页面也就展现到了屏幕上

渲染层提升为合成层有一个先决条件,该渲染层必须是 selfpaintinglayer

硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)

3d 或者 硬件加速的 2d canvas 元素

覆盖在 video 元素上的视频控制栏

video 元素

有 3d transform

backface-visibility 为 hidden

对 opacity、transform、fliter、backdropfilter 应用了 animation 或者 transition

renderobjects 保持了树结构,一个 renderobjects 知道如何绘制一个 node 的内容, 他通过向一个绘图上下文(graphicscontext)发出必要的绘制调用来绘制 nodes。

dom 树中得每个 node 节点都有一个对应的 layoutobject 。layoutobject 知道如何在屏幕上 paint node 的内容。

javascript -style- layout- paint- composite

javascript -style- paint- composite

javascript -style- composite

renderobject变成了layoutobject,renderlayer变成了paintlayer渲染层)

paintlayer(渲染层)->graphicslayers(合成层)

reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow

repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变visibility:hidden 只会触发 repaint,因为没有发现位置变化

url